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-2017, 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/htup_details.h"
21 : #include "access/xact.h"
22 : #include "bootstrap/bootstrap.h"
23 : #include "catalog/index.h"
24 : #include "catalog/pg_collation.h"
25 : #include "catalog/pg_type.h"
26 : #include "libpq/pqsignal.h"
27 : #include "miscadmin.h"
28 : #include "nodes/makefuncs.h"
29 : #include "pg_getopt.h"
30 : #include "pgstat.h"
31 : #include "postmaster/bgwriter.h"
32 : #include "postmaster/startup.h"
33 : #include "postmaster/walwriter.h"
34 : #include "replication/walreceiver.h"
35 : #include "storage/bufmgr.h"
36 : #include "storage/bufpage.h"
37 : #include "storage/condition_variable.h"
38 : #include "storage/ipc.h"
39 : #include "storage/proc.h"
40 : #include "tcop/tcopprot.h"
41 : #include "utils/builtins.h"
42 : #include "utils/fmgroids.h"
43 : #include "utils/memutils.h"
44 : #include "utils/ps_status.h"
45 : #include "utils/rel.h"
46 : #include "utils/relmapper.h"
47 : #include "utils/tqual.h"
48 :
49 : uint32 bootstrap_data_checksum_version = 0; /* No checksum */
50 :
51 :
52 : #define ALLOC(t, c) \
53 : ((t *) MemoryContextAllocZero(TopMemoryContext, (unsigned)(c) * sizeof(t)))
54 :
55 : static void CheckerModeMain(void);
56 : static void BootstrapModeMain(void);
57 : static void bootstrap_signals(void);
58 : static void ShutdownAuxiliaryProcess(int code, Datum arg);
59 : static Form_pg_attribute AllocateAttribute(void);
60 : static Oid gettype(char *type);
61 : static void cleanup(void);
62 :
63 : /* ----------------
64 : * global variables
65 : * ----------------
66 : */
67 :
68 : AuxProcType MyAuxProcType = NotAnAuxProcess; /* declared in miscadmin.h */
69 :
70 : Relation boot_reldesc; /* current relation descriptor */
71 :
72 : Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */
73 : int numattr; /* number of attributes for cur. rel */
74 :
75 :
76 : /*
77 : * Basic information associated with each type. This is used before
78 : * pg_type is filled, so it has to cover the datatypes used as column types
79 : * in the core "bootstrapped" catalogs.
80 : *
81 : * XXX several of these input/output functions do catalog scans
82 : * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some
83 : * order dependencies in the catalog creation process.
84 : */
85 : struct typinfo
86 : {
87 : char name[NAMEDATALEN];
88 : Oid oid;
89 : Oid elem;
90 : int16 len;
91 : bool byval;
92 : char align;
93 : char storage;
94 : Oid collation;
95 : Oid inproc;
96 : Oid outproc;
97 : };
98 :
99 : static const struct typinfo TypInfo[] = {
100 : {"bool", BOOLOID, 0, 1, true, 'c', 'p', InvalidOid,
101 : F_BOOLIN, F_BOOLOUT},
102 : {"bytea", BYTEAOID, 0, -1, false, 'i', 'x', InvalidOid,
103 : F_BYTEAIN, F_BYTEAOUT},
104 : {"char", CHAROID, 0, 1, true, 'c', 'p', InvalidOid,
105 : F_CHARIN, F_CHAROUT},
106 : {"int2", INT2OID, 0, 2, true, 's', 'p', InvalidOid,
107 : F_INT2IN, F_INT2OUT},
108 : {"int4", INT4OID, 0, 4, true, 'i', 'p', InvalidOid,
109 : F_INT4IN, F_INT4OUT},
110 : {"float4", FLOAT4OID, 0, 4, FLOAT4PASSBYVAL, 'i', 'p', InvalidOid,
111 : F_FLOAT4IN, F_FLOAT4OUT},
112 : {"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'c', 'p', InvalidOid,
113 : F_NAMEIN, F_NAMEOUT},
114 : {"regclass", REGCLASSOID, 0, 4, true, 'i', 'p', InvalidOid,
115 : F_REGCLASSIN, F_REGCLASSOUT},
116 : {"regproc", REGPROCOID, 0, 4, true, 'i', 'p', InvalidOid,
117 : F_REGPROCIN, F_REGPROCOUT},
118 : {"regtype", REGTYPEOID, 0, 4, true, 'i', 'p', InvalidOid,
119 : F_REGTYPEIN, F_REGTYPEOUT},
120 : {"regrole", REGROLEOID, 0, 4, true, 'i', 'p', InvalidOid,
121 : F_REGROLEIN, F_REGROLEOUT},
122 : {"regnamespace", REGNAMESPACEOID, 0, 4, true, 'i', 'p', InvalidOid,
123 : F_REGNAMESPACEIN, F_REGNAMESPACEOUT},
124 : {"text", TEXTOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
125 : F_TEXTIN, F_TEXTOUT},
126 : {"oid", OIDOID, 0, 4, true, 'i', 'p', InvalidOid,
127 : F_OIDIN, F_OIDOUT},
128 : {"tid", TIDOID, 0, 6, false, 's', 'p', InvalidOid,
129 : F_TIDIN, F_TIDOUT},
130 : {"xid", XIDOID, 0, 4, true, 'i', 'p', InvalidOid,
131 : F_XIDIN, F_XIDOUT},
132 : {"cid", CIDOID, 0, 4, true, 'i', 'p', InvalidOid,
133 : F_CIDIN, F_CIDOUT},
134 : {"pg_node_tree", PGNODETREEOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
135 : F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT},
136 : {"int2vector", INT2VECTOROID, INT2OID, -1, false, 'i', 'p', InvalidOid,
137 : F_INT2VECTORIN, F_INT2VECTOROUT},
138 : {"oidvector", OIDVECTOROID, OIDOID, -1, false, 'i', 'p', InvalidOid,
139 : F_OIDVECTORIN, F_OIDVECTOROUT},
140 : {"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x', InvalidOid,
141 : F_ARRAY_IN, F_ARRAY_OUT},
142 : {"_text", 1009, TEXTOID, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
143 : F_ARRAY_IN, F_ARRAY_OUT},
144 : {"_oid", 1028, OIDOID, -1, false, 'i', 'x', InvalidOid,
145 : F_ARRAY_IN, F_ARRAY_OUT},
146 : {"_char", 1002, CHAROID, -1, false, 'i', 'x', InvalidOid,
147 : F_ARRAY_IN, F_ARRAY_OUT},
148 : {"_aclitem", 1034, ACLITEMOID, -1, false, 'i', 'x', InvalidOid,
149 : F_ARRAY_IN, F_ARRAY_OUT}
150 : };
151 :
152 : static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);
153 :
154 : struct typmap
155 : { /* a hack */
156 : Oid am_oid;
157 : FormData_pg_type am_typ;
158 : };
159 :
160 : static struct typmap **Typ = NULL;
161 : static struct typmap *Ap = NULL;
162 :
163 : static Datum values[MAXATTR]; /* current row's attribute values */
164 : static bool Nulls[MAXATTR];
165 :
166 : static MemoryContext nogc = NULL; /* special no-gc mem context */
167 :
168 : /*
169 : * At bootstrap time, we first declare all the indices to be built, and
170 : * then build them. The IndexList structure stores enough information
171 : * to allow us to build the indices after they've been declared.
172 : */
173 :
174 : typedef struct _IndexList
175 : {
176 : Oid il_heap;
177 : Oid il_ind;
178 : IndexInfo *il_info;
179 : struct _IndexList *il_next;
180 : } IndexList;
181 :
182 : static IndexList *ILHead = NULL;
183 :
184 :
185 : /*
186 : * AuxiliaryProcessMain
187 : *
188 : * The main entry point for auxiliary processes, such as the bgwriter,
189 : * walwriter, walreceiver, bootstrapper and the shared memory checker code.
190 : *
191 : * This code is here just because of historical reasons.
192 : */
193 : void
194 7 : AuxiliaryProcessMain(int argc, char *argv[])
195 : {
196 7 : char *progname = argv[0];
197 : int flag;
198 7 : char *userDoption = NULL;
199 :
200 : /*
201 : * Initialize process environment (already done if under postmaster, but
202 : * not if standalone).
203 : */
204 7 : if (!IsUnderPostmaster)
205 3 : InitStandaloneProcess(argv[0]);
206 :
207 : /*
208 : * process command arguments
209 : */
210 :
211 : /* Set defaults, to be overridden by explicit options below */
212 7 : if (!IsUnderPostmaster)
213 3 : InitializeGUCOptions();
214 :
215 : /* Ignore the initial --boot argument, if present */
216 7 : if (argc > 1 && strcmp(argv[1], "--boot") == 0)
217 : {
218 3 : argv++;
219 3 : argc--;
220 : }
221 :
222 : /* If no -x argument, we are a CheckerProcess */
223 7 : MyAuxProcType = CheckerProcess;
224 :
225 30 : 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 'D':
233 0 : userDoption = pstrdup(optarg);
234 0 : break;
235 : case 'd':
236 : {
237 : /* Turn on debugging for the bootstrap process. */
238 : char *debugstr;
239 :
240 0 : debugstr = psprintf("debug%s", optarg);
241 0 : SetConfigOption("log_min_messages", debugstr,
242 : PGC_POSTMASTER, PGC_S_ARGV);
243 0 : SetConfigOption("client_min_messages", debugstr,
244 : PGC_POSTMASTER, PGC_S_ARGV);
245 0 : pfree(debugstr);
246 : }
247 0 : break;
248 : case 'F':
249 3 : SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
250 3 : break;
251 : case 'k':
252 0 : bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
253 0 : break;
254 : case 'r':
255 0 : strlcpy(OutputFileName, optarg, MAXPGPATH);
256 0 : break;
257 : case 'x':
258 7 : MyAuxProcType = atoi(optarg);
259 7 : break;
260 : case 'c':
261 : case '-':
262 : {
263 : char *name,
264 : *value;
265 :
266 6 : ParseLongOption(optarg, &name, &value);
267 6 : if (!value)
268 : {
269 0 : if (flag == '-')
270 0 : ereport(ERROR,
271 : (errcode(ERRCODE_SYNTAX_ERROR),
272 : errmsg("--%s requires a value",
273 : optarg)));
274 : else
275 0 : ereport(ERROR,
276 : (errcode(ERRCODE_SYNTAX_ERROR),
277 : errmsg("-c %s requires a value",
278 : optarg)));
279 : }
280 :
281 6 : SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
282 6 : free(name);
283 6 : if (value)
284 6 : free(value);
285 6 : break;
286 : }
287 : default:
288 0 : write_stderr("Try \"%s --help\" for more information.\n",
289 : progname);
290 0 : proc_exit(1);
291 : break;
292 : }
293 : }
294 :
295 7 : if (argc != optind)
296 : {
297 0 : write_stderr("%s: invalid command-line arguments\n", progname);
298 0 : proc_exit(1);
299 : }
300 :
301 : /*
302 : * Identify myself via ps
303 : */
304 7 : if (IsUnderPostmaster)
305 : {
306 : const char *statmsg;
307 :
308 4 : switch (MyAuxProcType)
309 : {
310 : case StartupProcess:
311 1 : statmsg = "startup process";
312 1 : break;
313 : case BgWriterProcess:
314 1 : statmsg = "writer process";
315 1 : break;
316 : case CheckpointerProcess:
317 1 : statmsg = "checkpointer process";
318 1 : break;
319 : case WalWriterProcess:
320 1 : statmsg = "wal writer process";
321 1 : break;
322 : case WalReceiverProcess:
323 0 : statmsg = "wal receiver process";
324 0 : break;
325 : default:
326 0 : statmsg = "??? process";
327 0 : break;
328 : }
329 4 : init_ps_display(statmsg, "", "", "");
330 : }
331 :
332 : /* Acquire configuration parameters, unless inherited from postmaster */
333 7 : if (!IsUnderPostmaster)
334 : {
335 3 : if (!SelectConfigFiles(userDoption, progname))
336 0 : proc_exit(1);
337 : }
338 :
339 : /* Validate we have been given a reasonable-looking DataDir */
340 7 : Assert(DataDir);
341 7 : ValidatePgVersion(DataDir);
342 :
343 : /* Change into DataDir (if under postmaster, should be done already) */
344 7 : if (!IsUnderPostmaster)
345 3 : ChangeToDataDir();
346 :
347 : /* If standalone, create lockfile for data directory */
348 7 : if (!IsUnderPostmaster)
349 3 : CreateDataDirLockFile(false);
350 :
351 7 : SetProcessingMode(BootstrapProcessing);
352 7 : IgnoreSystemIndexes = true;
353 :
354 : /* Initialize MaxBackends (if under postmaster, was done already) */
355 7 : if (!IsUnderPostmaster)
356 3 : InitializeMaxBackends();
357 :
358 7 : BaseInit();
359 :
360 : /*
361 : * When we are an auxiliary process, we aren't going to do the full
362 : * InitPostgres pushups, but there are a couple of things that need to get
363 : * lit up even in an auxiliary process.
364 : */
365 7 : if (IsUnderPostmaster)
366 : {
367 : /*
368 : * Create a PGPROC so we can use LWLocks. In the EXEC_BACKEND case,
369 : * this was already done by SubPostmasterMain().
370 : */
371 : #ifndef EXEC_BACKEND
372 4 : InitAuxiliaryProcess();
373 : #endif
374 :
375 : /*
376 : * Assign the ProcSignalSlot for an auxiliary process. Since it
377 : * doesn't have a BackendId, the slot is statically allocated based on
378 : * the auxiliary process type (MyAuxProcType). Backends use slots
379 : * indexed in the range from 1 to MaxBackends (inclusive), so we use
380 : * MaxBackends + AuxProcType + 1 as the index of the slot for an
381 : * auxiliary process.
382 : *
383 : * This will need rethinking if we ever want more than one of a
384 : * particular auxiliary process type.
385 : */
386 4 : ProcSignalInit(MaxBackends + MyAuxProcType + 1);
387 :
388 : /* finish setting up bufmgr.c */
389 4 : InitBufferPoolBackend();
390 :
391 : /* Initialize backend status information */
392 4 : pgstat_initialize();
393 4 : pgstat_bestart();
394 :
395 : /* register a before-shutdown callback for LWLock cleanup */
396 4 : before_shmem_exit(ShutdownAuxiliaryProcess, 0);
397 : }
398 :
399 : /*
400 : * XLOG operations
401 : */
402 7 : SetProcessingMode(NormalProcessing);
403 :
404 7 : switch (MyAuxProcType)
405 : {
406 : case CheckerProcess:
407 : /* don't set signals, they're useless here */
408 2 : CheckerModeMain();
409 0 : proc_exit(1); /* should never return */
410 :
411 : case BootstrapProcess:
412 :
413 : /*
414 : * There was a brief instant during which mode was Normal; this is
415 : * okay. We need to be in bootstrap mode during BootStrapXLOG for
416 : * the sake of multixact initialization.
417 : */
418 1 : SetProcessingMode(BootstrapProcessing);
419 1 : bootstrap_signals();
420 1 : BootStrapXLOG();
421 1 : BootstrapModeMain();
422 0 : proc_exit(1); /* should never return */
423 :
424 : case StartupProcess:
425 : /* don't set signals, startup process has its own agenda */
426 1 : StartupProcessMain();
427 : proc_exit(1); /* should never return */
428 :
429 : case BgWriterProcess:
430 : /* don't set signals, bgwriter has its own agenda */
431 1 : BackgroundWriterMain();
432 : proc_exit(1); /* should never return */
433 :
434 : case CheckpointerProcess:
435 : /* don't set signals, checkpointer has its own agenda */
436 1 : CheckpointerMain();
437 : proc_exit(1); /* should never return */
438 :
439 : case WalWriterProcess:
440 : /* don't set signals, walwriter has its own agenda */
441 1 : InitXLOGAccess();
442 1 : WalWriterMain();
443 : proc_exit(1); /* should never return */
444 :
445 : case WalReceiverProcess:
446 : /* don't set signals, walreceiver has its own agenda */
447 0 : WalReceiverMain();
448 : proc_exit(1); /* should never return */
449 :
450 : default:
451 0 : elog(PANIC, "unrecognized process type: %d", (int) MyAuxProcType);
452 : proc_exit(1);
453 : }
454 : }
455 :
456 : /*
457 : * In shared memory checker mode, all we really want to do is create shared
458 : * memory and semaphores (just to prove we can do it with the current GUC
459 : * settings). Since, in fact, that was already done by BaseInit(),
460 : * we have nothing more to do here.
461 : */
462 : static void
463 2 : CheckerModeMain(void)
464 : {
465 2 : proc_exit(0);
466 : }
467 :
468 : /*
469 : * The main entry point for running the backend in bootstrap mode
470 : *
471 : * The bootstrap mode is used to initialize the template database.
472 : * The bootstrap backend doesn't speak SQL, but instead expects
473 : * commands in a special bootstrap language.
474 : */
475 : static void
476 1 : BootstrapModeMain(void)
477 : {
478 : int i;
479 :
480 1 : Assert(!IsUnderPostmaster);
481 1 : Assert(IsBootstrapProcessingMode());
482 :
483 : /*
484 : * Do backend-like initialization for bootstrap mode
485 : */
486 1 : InitProcess();
487 :
488 1 : InitPostgres(NULL, InvalidOid, NULL, InvalidOid, NULL);
489 :
490 : /* Initialize stuff for bootstrap-file processing */
491 41 : for (i = 0; i < MAXATTR; i++)
492 : {
493 40 : attrtypes[i] = NULL;
494 40 : Nulls[i] = false;
495 : }
496 :
497 : /*
498 : * Process bootstrap input.
499 : */
500 1 : StartTransactionCommand();
501 1 : boot_yyparse();
502 1 : CommitTransactionCommand();
503 :
504 : /*
505 : * We should now know about all mapped relations, so it's okay to write
506 : * out the initial relation mapping files.
507 : */
508 1 : RelationMapFinishBootstrap();
509 :
510 : /* Clean up and exit */
511 1 : cleanup();
512 1 : proc_exit(0);
513 : }
514 :
515 :
516 : /* ----------------------------------------------------------------
517 : * misc functions
518 : * ----------------------------------------------------------------
519 : */
520 :
521 : /*
522 : * Set up signal handling for a bootstrap process
523 : */
524 : static void
525 1 : bootstrap_signals(void)
526 : {
527 1 : Assert(!IsUnderPostmaster);
528 :
529 : /* Set up appropriately for interactive use */
530 1 : pqsignal(SIGHUP, die);
531 1 : pqsignal(SIGINT, die);
532 1 : pqsignal(SIGTERM, die);
533 1 : pqsignal(SIGQUIT, die);
534 1 : }
535 :
536 : /*
537 : * Begin shutdown of an auxiliary process. This is approximately the equivalent
538 : * of ShutdownPostgres() in postinit.c. We can't run transactions in an
539 : * auxiliary process, so most of the work of AbortTransaction() is not needed,
540 : * but we do need to make sure we've released any LWLocks we are holding.
541 : * (This is only critical during an error exit.)
542 : */
543 : static void
544 4 : ShutdownAuxiliaryProcess(int code, Datum arg)
545 : {
546 4 : LWLockReleaseAll();
547 4 : ConditionVariableCancelSleep();
548 4 : pgstat_report_wait_end();
549 4 : }
550 :
551 : /* ----------------------------------------------------------------
552 : * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
553 : * ----------------------------------------------------------------
554 : */
555 :
556 : /* ----------------
557 : * boot_openrel
558 : * ----------------
559 : */
560 : void
561 58 : boot_openrel(char *relname)
562 : {
563 : int i;
564 : struct typmap **app;
565 : Relation rel;
566 : HeapScanDesc scan;
567 : HeapTuple tup;
568 :
569 58 : if (strlen(relname) >= NAMEDATALEN)
570 0 : relname[NAMEDATALEN - 1] = '\0';
571 :
572 58 : if (Typ == NULL)
573 : {
574 : /* We can now load the pg_type data */
575 1 : rel = heap_open(TypeRelationId, NoLock);
576 1 : scan = heap_beginscan_catalog(rel, 0, NULL);
577 1 : i = 0;
578 170 : while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
579 168 : ++i;
580 1 : heap_endscan(scan);
581 1 : app = Typ = ALLOC(struct typmap *, i + 1);
582 170 : while (i-- > 0)
583 168 : *app++ = ALLOC(struct typmap, 1);
584 1 : *app = NULL;
585 1 : scan = heap_beginscan_catalog(rel, 0, NULL);
586 1 : app = Typ;
587 170 : while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
588 : {
589 168 : (*app)->am_oid = HeapTupleGetOid(tup);
590 336 : memcpy((char *) &(*app)->am_typ,
591 336 : (char *) GETSTRUCT(tup),
592 : sizeof((*app)->am_typ));
593 168 : app++;
594 : }
595 1 : heap_endscan(scan);
596 1 : heap_close(rel, NoLock);
597 : }
598 :
599 58 : if (boot_reldesc != NULL)
600 0 : closerel(NULL);
601 :
602 58 : elog(DEBUG4, "open relation %s, attrsize %d",
603 : relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
604 :
605 58 : boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
606 58 : numattr = boot_reldesc->rd_rel->relnatts;
607 459 : for (i = 0; i < numattr; i++)
608 : {
609 401 : if (attrtypes[i] == NULL)
610 0 : attrtypes[i] = AllocateAttribute();
611 401 : memmove((char *) attrtypes[i],
612 401 : (char *) TupleDescAttr(boot_reldesc->rd_att, i),
613 : ATTRIBUTE_FIXED_PART_SIZE);
614 :
615 : {
616 401 : Form_pg_attribute at = attrtypes[i];
617 :
618 401 : elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
619 : i, NameStr(at->attname), at->attlen, at->attnum,
620 : at->atttypid);
621 : }
622 : }
623 58 : }
624 :
625 : /* ----------------
626 : * closerel
627 : * ----------------
628 : */
629 : void
630 62 : closerel(char *name)
631 : {
632 62 : if (name)
633 : {
634 62 : if (boot_reldesc)
635 : {
636 62 : if (strcmp(RelationGetRelationName(boot_reldesc), name) != 0)
637 0 : elog(ERROR, "close of %s when %s was expected",
638 : name, RelationGetRelationName(boot_reldesc));
639 : }
640 : else
641 0 : elog(ERROR, "close of %s before any relation was opened",
642 : name);
643 : }
644 :
645 62 : if (boot_reldesc == NULL)
646 0 : elog(ERROR, "no open relation to close");
647 : else
648 : {
649 62 : elog(DEBUG4, "close relation %s",
650 : RelationGetRelationName(boot_reldesc));
651 62 : heap_close(boot_reldesc, NoLock);
652 62 : boot_reldesc = NULL;
653 : }
654 62 : }
655 :
656 :
657 :
658 : /* ----------------
659 : * DEFINEATTR()
660 : *
661 : * define a <field,type> pair
662 : * if there are n fields in a relation to be created, this routine
663 : * will be called n times
664 : * ----------------
665 : */
666 : void
667 515 : DefineAttr(char *name, char *type, int attnum, int nullness)
668 : {
669 : Oid typeoid;
670 :
671 515 : if (boot_reldesc != NULL)
672 : {
673 0 : elog(WARNING, "no open relations allowed with CREATE command");
674 0 : closerel(NULL);
675 : }
676 :
677 515 : if (attrtypes[attnum] == NULL)
678 33 : attrtypes[attnum] = AllocateAttribute();
679 515 : MemSet(attrtypes[attnum], 0, ATTRIBUTE_FIXED_PART_SIZE);
680 :
681 515 : namestrcpy(&attrtypes[attnum]->attname, name);
682 515 : elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
683 515 : attrtypes[attnum]->attnum = attnum + 1; /* fillatt */
684 :
685 515 : typeoid = gettype(type);
686 :
687 515 : if (Typ != NULL)
688 : {
689 397 : attrtypes[attnum]->atttypid = Ap->am_oid;
690 397 : attrtypes[attnum]->attlen = Ap->am_typ.typlen;
691 397 : attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
692 397 : attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
693 397 : attrtypes[attnum]->attalign = Ap->am_typ.typalign;
694 397 : attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
695 : /* if an array type, assume 1-dimensional attribute */
696 397 : if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
697 42 : attrtypes[attnum]->attndims = 1;
698 : else
699 355 : attrtypes[attnum]->attndims = 0;
700 : }
701 : else
702 : {
703 118 : attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
704 118 : attrtypes[attnum]->attlen = TypInfo[typeoid].len;
705 118 : attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
706 118 : attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
707 118 : attrtypes[attnum]->attalign = TypInfo[typeoid].align;
708 118 : attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
709 : /* if an array type, assume 1-dimensional attribute */
710 135 : if (TypInfo[typeoid].elem != InvalidOid &&
711 17 : attrtypes[attnum]->attlen < 0)
712 13 : attrtypes[attnum]->attndims = 1;
713 : else
714 105 : attrtypes[attnum]->attndims = 0;
715 : }
716 :
717 515 : attrtypes[attnum]->attstattarget = -1;
718 515 : attrtypes[attnum]->attcacheoff = -1;
719 515 : attrtypes[attnum]->atttypmod = -1;
720 515 : attrtypes[attnum]->attislocal = true;
721 :
722 515 : if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
723 : {
724 18 : attrtypes[attnum]->attnotnull = true;
725 : }
726 497 : else if (nullness == BOOTCOL_NULL_FORCE_NULL)
727 : {
728 0 : attrtypes[attnum]->attnotnull = false;
729 : }
730 : else
731 : {
732 497 : Assert(nullness == BOOTCOL_NULL_AUTO);
733 :
734 : /*
735 : * Mark as "not null" if type is fixed-width and prior columns are
736 : * too. This corresponds to case where column can be accessed
737 : * directly via C struct declaration.
738 : *
739 : * oidvector and int2vector are also treated as not-nullable, even
740 : * though they are no longer fixed-width.
741 : */
742 : #define MARKNOTNULL(att) \
743 : ((att)->attlen > 0 || \
744 : (att)->atttypid == OIDVECTOROID || \
745 : (att)->atttypid == INT2VECTOROID)
746 :
747 497 : if (MARKNOTNULL(attrtypes[attnum]))
748 : {
749 : int i;
750 :
751 : /* check earlier attributes */
752 2828 : for (i = 0; i < attnum; i++)
753 : {
754 2409 : if (!attrtypes[i]->attnotnull)
755 3 : break;
756 : }
757 422 : if (i == attnum)
758 419 : attrtypes[attnum]->attnotnull = true;
759 : }
760 : }
761 515 : }
762 :
763 :
764 : /* ----------------
765 : * InsertOneTuple
766 : *
767 : * If objectid is not zero, it is a specific OID to assign to the tuple.
768 : * Otherwise, an OID will be assigned (if necessary) by heap_insert.
769 : * ----------------
770 : */
771 : void
772 5738 : InsertOneTuple(Oid objectid)
773 : {
774 : HeapTuple tuple;
775 : TupleDesc tupDesc;
776 : int i;
777 :
778 5738 : elog(DEBUG4, "inserting row oid %u, %d columns", objectid, numattr);
779 :
780 5738 : tupDesc = CreateTupleDesc(numattr,
781 5738 : RelationGetForm(boot_reldesc)->relhasoids,
782 : attrtypes);
783 5738 : tuple = heap_form_tuple(tupDesc, values, Nulls);
784 5738 : if (objectid != (Oid) 0)
785 3928 : HeapTupleSetOid(tuple, objectid);
786 5738 : pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
787 :
788 5738 : simple_heap_insert(boot_reldesc, tuple);
789 5738 : heap_freetuple(tuple);
790 5738 : elog(DEBUG4, "row inserted");
791 :
792 : /*
793 : * Reset null markers for next tuple
794 : */
795 120262 : for (i = 0; i < numattr; i++)
796 114524 : Nulls[i] = false;
797 5738 : }
798 :
799 : /* ----------------
800 : * InsertOneValue
801 : * ----------------
802 : */
803 : void
804 91074 : InsertOneValue(char *value, int i)
805 : {
806 : Oid typoid;
807 : int16 typlen;
808 : bool typbyval;
809 : char typalign;
810 : char typdelim;
811 : Oid typioparam;
812 : Oid typinput;
813 : Oid typoutput;
814 :
815 91074 : AssertArg(i >= 0 && i < MAXATTR);
816 :
817 91074 : elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
818 :
819 91074 : typoid = TupleDescAttr(boot_reldesc->rd_att, i)->atttypid;
820 :
821 91074 : boot_get_type_io_data(typoid,
822 : &typlen, &typbyval, &typalign,
823 : &typdelim, &typioparam,
824 : &typinput, &typoutput);
825 :
826 91074 : values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
827 :
828 : /*
829 : * We use ereport not elog here so that parameters aren't evaluated unless
830 : * the message is going to be printed, which generally it isn't
831 : */
832 91074 : ereport(DEBUG4,
833 : (errmsg_internal("inserted -> %s",
834 : OidOutputFunctionCall(typoutput, values[i]))));
835 91074 : }
836 :
837 : /* ----------------
838 : * InsertOneNull
839 : * ----------------
840 : */
841 : void
842 23450 : InsertOneNull(int i)
843 : {
844 23450 : elog(DEBUG4, "inserting column %d NULL", i);
845 23450 : Assert(i >= 0 && i < MAXATTR);
846 23450 : if (TupleDescAttr(boot_reldesc->rd_att, i)->attnotnull)
847 0 : elog(ERROR,
848 : "NULL value specified for not-null column \"%s\" of relation \"%s\"",
849 : NameStr(TupleDescAttr(boot_reldesc->rd_att, i)->attname),
850 : RelationGetRelationName(boot_reldesc));
851 23450 : values[i] = PointerGetDatum(NULL);
852 23450 : Nulls[i] = true;
853 23450 : }
854 :
855 : /* ----------------
856 : * cleanup
857 : * ----------------
858 : */
859 : static void
860 1 : cleanup(void)
861 : {
862 1 : if (boot_reldesc != NULL)
863 0 : closerel(NULL);
864 1 : }
865 :
866 : /* ----------------
867 : * gettype
868 : *
869 : * NB: this is really ugly; it will return an integer index into TypInfo[],
870 : * and not an OID at all, until the first reference to a type not known in
871 : * TypInfo[]. At that point it will read and cache pg_type in the Typ array,
872 : * and subsequently return a real OID (and set the global pointer Ap to
873 : * point at the found row in Typ). So caller must check whether Typ is
874 : * still NULL to determine what the return value is!
875 : * ----------------
876 : */
877 : static Oid
878 515 : gettype(char *type)
879 : {
880 : int i;
881 : Relation rel;
882 : HeapScanDesc scan;
883 : HeapTuple tup;
884 : struct typmap **app;
885 :
886 515 : if (Typ != NULL)
887 : {
888 6148 : for (app = Typ; *app != NULL; app++)
889 : {
890 6148 : if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0)
891 : {
892 397 : Ap = *app;
893 397 : return (*app)->am_oid;
894 : }
895 : }
896 : }
897 : else
898 : {
899 1052 : for (i = 0; i < n_types; i++)
900 : {
901 1052 : if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
902 118 : return i;
903 : }
904 0 : elog(DEBUG4, "external type: %s", type);
905 0 : rel = heap_open(TypeRelationId, NoLock);
906 0 : scan = heap_beginscan_catalog(rel, 0, NULL);
907 0 : i = 0;
908 0 : while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
909 0 : ++i;
910 0 : heap_endscan(scan);
911 0 : app = Typ = ALLOC(struct typmap *, i + 1);
912 0 : while (i-- > 0)
913 0 : *app++ = ALLOC(struct typmap, 1);
914 0 : *app = NULL;
915 0 : scan = heap_beginscan_catalog(rel, 0, NULL);
916 0 : app = Typ;
917 0 : while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
918 : {
919 0 : (*app)->am_oid = HeapTupleGetOid(tup);
920 0 : memmove((char *) &(*app++)->am_typ,
921 0 : (char *) GETSTRUCT(tup),
922 : sizeof((*app)->am_typ));
923 : }
924 0 : heap_endscan(scan);
925 0 : heap_close(rel, NoLock);
926 0 : return gettype(type);
927 : }
928 0 : elog(ERROR, "unrecognized type \"%s\"", type);
929 : /* not reached, here to make compiler happy */
930 : return 0;
931 : }
932 :
933 : /* ----------------
934 : * boot_get_type_io_data
935 : *
936 : * Obtain type I/O information at bootstrap time. This intentionally has
937 : * almost the same API as lsyscache.c's get_type_io_data, except that
938 : * we only support obtaining the typinput and typoutput routines, not
939 : * the binary I/O routines. It is exported so that array_in and array_out
940 : * can be made to work during early bootstrap.
941 : * ----------------
942 : */
943 : void
944 91349 : boot_get_type_io_data(Oid typid,
945 : int16 *typlen,
946 : bool *typbyval,
947 : char *typalign,
948 : char *typdelim,
949 : Oid *typioparam,
950 : Oid *typinput,
951 : Oid *typoutput)
952 : {
953 91349 : if (Typ != NULL)
954 : {
955 : /* We have the boot-time contents of pg_type, so use it */
956 : struct typmap **app;
957 : struct typmap *ap;
958 :
959 24397 : app = Typ;
960 232383 : while (*app && (*app)->am_oid != typid)
961 183589 : ++app;
962 24397 : ap = *app;
963 24397 : if (ap == NULL)
964 0 : elog(ERROR, "type OID %u not found in Typ list", typid);
965 :
966 24397 : *typlen = ap->am_typ.typlen;
967 24397 : *typbyval = ap->am_typ.typbyval;
968 24397 : *typalign = ap->am_typ.typalign;
969 24397 : *typdelim = ap->am_typ.typdelim;
970 :
971 : /* XXX this logic must match getTypeIOParam() */
972 24397 : if (OidIsValid(ap->am_typ.typelem))
973 1082 : *typioparam = ap->am_typ.typelem;
974 : else
975 23315 : *typioparam = typid;
976 :
977 24397 : *typinput = ap->am_typ.typinput;
978 24397 : *typoutput = ap->am_typ.typoutput;
979 : }
980 : else
981 : {
982 : /* We don't have pg_type yet, so use the hard-wired TypInfo array */
983 : int typeindex;
984 :
985 481894 : for (typeindex = 0; typeindex < n_types; typeindex++)
986 : {
987 481894 : if (TypInfo[typeindex].oid == typid)
988 66952 : break;
989 : }
990 66952 : if (typeindex >= n_types)
991 0 : elog(ERROR, "type OID %u not found in TypInfo", typid);
992 :
993 66952 : *typlen = TypInfo[typeindex].len;
994 66952 : *typbyval = TypInfo[typeindex].byval;
995 66952 : *typalign = TypInfo[typeindex].align;
996 : /* We assume typdelim is ',' for all boot-time types */
997 66952 : *typdelim = ',';
998 :
999 : /* XXX this logic must match getTypeIOParam() */
1000 66952 : if (OidIsValid(TypInfo[typeindex].elem))
1001 6215 : *typioparam = TypInfo[typeindex].elem;
1002 : else
1003 60737 : *typioparam = typid;
1004 :
1005 66952 : *typinput = TypInfo[typeindex].inproc;
1006 66952 : *typoutput = TypInfo[typeindex].outproc;
1007 : }
1008 91349 : }
1009 :
1010 : /* ----------------
1011 : * AllocateAttribute
1012 : *
1013 : * Note: bootstrap never sets any per-column ACLs, so we only need
1014 : * ATTRIBUTE_FIXED_PART_SIZE space per attribute.
1015 : * ----------------
1016 : */
1017 : static Form_pg_attribute
1018 33 : AllocateAttribute(void)
1019 : {
1020 33 : return (Form_pg_attribute)
1021 33 : MemoryContextAllocZero(TopMemoryContext, ATTRIBUTE_FIXED_PART_SIZE);
1022 : }
1023 :
1024 : /*
1025 : * MapArrayTypeName
1026 : *
1027 : * Given a type name, produce the corresponding array type name by prepending
1028 : * '_' and truncating as needed to fit in NAMEDATALEN-1 bytes. This is only
1029 : * used in bootstrap mode, so we can get away with assuming that the input is
1030 : * ASCII and we don't need multibyte-aware truncation.
1031 : *
1032 : * The given string normally ends with '[]' or '[digits]'; we discard that.
1033 : *
1034 : * The result is a palloc'd string.
1035 : */
1036 : char *
1037 45 : MapArrayTypeName(const char *s)
1038 : {
1039 : int i,
1040 : j;
1041 : char newStr[NAMEDATALEN];
1042 :
1043 45 : newStr[0] = '_';
1044 45 : j = 1;
1045 269 : for (i = 0; i < NAMEDATALEN - 2 && s[i] != '['; i++, j++)
1046 224 : newStr[j] = s[i];
1047 :
1048 45 : newStr[j] = '\0';
1049 :
1050 45 : return pstrdup(newStr);
1051 : }
1052 :
1053 :
1054 : /*
1055 : * index_register() -- record an index that has been set up for building
1056 : * later.
1057 : *
1058 : * At bootstrap time, we define a bunch of indexes on system catalogs.
1059 : * We postpone actually building the indexes until just before we're
1060 : * finished with initialization, however. This is because the indexes
1061 : * themselves have catalog entries, and those have to be included in the
1062 : * indexes on those catalogs. Doing it in two phases is the simplest
1063 : * way of making sure the indexes have the right contents at the end.
1064 : */
1065 : void
1066 127 : index_register(Oid heap,
1067 : Oid ind,
1068 : IndexInfo *indexInfo)
1069 : {
1070 : IndexList *newind;
1071 : MemoryContext oldcxt;
1072 :
1073 : /*
1074 : * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
1075 : * bootstrap time. we'll declare the indexes now, but want to create them
1076 : * later.
1077 : */
1078 :
1079 127 : if (nogc == NULL)
1080 1 : nogc = AllocSetContextCreate(NULL,
1081 : "BootstrapNoGC",
1082 : ALLOCSET_DEFAULT_SIZES);
1083 :
1084 127 : oldcxt = MemoryContextSwitchTo(nogc);
1085 :
1086 127 : newind = (IndexList *) palloc(sizeof(IndexList));
1087 127 : newind->il_heap = heap;
1088 127 : newind->il_ind = ind;
1089 127 : newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
1090 :
1091 127 : memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
1092 : /* expressions will likely be null, but may as well copy it */
1093 254 : newind->il_info->ii_Expressions =
1094 127 : copyObject(indexInfo->ii_Expressions);
1095 127 : newind->il_info->ii_ExpressionsState = NIL;
1096 : /* predicate will likely be null, but may as well copy it */
1097 254 : newind->il_info->ii_Predicate =
1098 127 : copyObject(indexInfo->ii_Predicate);
1099 127 : newind->il_info->ii_PredicateState = NULL;
1100 : /* no exclusion constraints at bootstrap time, so no need to copy */
1101 127 : Assert(indexInfo->ii_ExclusionOps == NULL);
1102 127 : Assert(indexInfo->ii_ExclusionProcs == NULL);
1103 127 : Assert(indexInfo->ii_ExclusionStrats == NULL);
1104 :
1105 127 : newind->il_next = ILHead;
1106 127 : ILHead = newind;
1107 :
1108 127 : MemoryContextSwitchTo(oldcxt);
1109 127 : }
1110 :
1111 :
1112 : /*
1113 : * build_indices -- fill in all the indexes registered earlier
1114 : */
1115 : void
1116 1 : build_indices(void)
1117 : {
1118 128 : for (; ILHead != NULL; ILHead = ILHead->il_next)
1119 : {
1120 : Relation heap;
1121 : Relation ind;
1122 :
1123 : /* need not bother with locks during bootstrap */
1124 127 : heap = heap_open(ILHead->il_heap, NoLock);
1125 127 : ind = index_open(ILHead->il_ind, NoLock);
1126 :
1127 127 : index_build(heap, ind, ILHead->il_info, false, false);
1128 :
1129 127 : index_close(ind, NoLock);
1130 127 : heap_close(heap, NoLock);
1131 : }
1132 1 : }
|