nbtree: fix read page recheck typo.
[pgsql.git] / src / backend / bootstrap / bootstrap.c
blobed59dfce89380e3ad4b441551cdc7a171c5057ce
1 /*-------------------------------------------------------------------------
3 * bootstrap.c
4 * routines to support running postgres in 'bootstrap' mode
5 * bootstrap mode is used to create the initial template database
7 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/bootstrap/bootstrap.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include <unistd.h>
18 #include <signal.h>
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 "storage/bufpage.h"
35 #include "storage/ipc.h"
36 #include "storage/proc.h"
37 #include "utils/builtins.h"
38 #include "utils/fmgroids.h"
39 #include "utils/guc.h"
40 #include "utils/memutils.h"
41 #include "utils/rel.h"
42 #include "utils/relmapper.h"
45 static void CheckerModeMain(void);
46 static void bootstrap_signals(void);
47 static Form_pg_attribute AllocateAttribute(void);
48 static void populate_typ_list(void);
49 static Oid gettype(char *type);
50 static void cleanup(void);
52 /* ----------------
53 * global variables
54 * ----------------
57 Relation boot_reldesc; /* current relation descriptor */
59 Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */
60 int numattr; /* number of attributes for cur. rel */
64 * Basic information associated with each type. This is used before
65 * pg_type is filled, so it has to cover the datatypes used as column types
66 * in the core "bootstrapped" catalogs.
68 * XXX several of these input/output functions do catalog scans
69 * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some
70 * order dependencies in the catalog creation process.
72 struct typinfo
74 char name[NAMEDATALEN];
75 Oid oid;
76 Oid elem;
77 int16 len;
78 bool byval;
79 char align;
80 char storage;
81 Oid collation;
82 Oid inproc;
83 Oid outproc;
86 static const struct typinfo TypInfo[] = {
87 {"bool", BOOLOID, 0, 1, true, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
88 F_BOOLIN, F_BOOLOUT},
89 {"bytea", BYTEAOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
90 F_BYTEAIN, F_BYTEAOUT},
91 {"char", CHAROID, 0, 1, true, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
92 F_CHARIN, F_CHAROUT},
93 {"int2", INT2OID, 0, 2, true, TYPALIGN_SHORT, TYPSTORAGE_PLAIN, InvalidOid,
94 F_INT2IN, F_INT2OUT},
95 {"int4", INT4OID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
96 F_INT4IN, F_INT4OUT},
97 {"float4", FLOAT4OID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
98 F_FLOAT4IN, F_FLOAT4OUT},
99 {"name", NAMEOID, CHAROID, NAMEDATALEN, false, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, C_COLLATION_OID,
100 F_NAMEIN, F_NAMEOUT},
101 {"regclass", REGCLASSOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
102 F_REGCLASSIN, F_REGCLASSOUT},
103 {"regproc", REGPROCOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
104 F_REGPROCIN, F_REGPROCOUT},
105 {"regtype", REGTYPEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
106 F_REGTYPEIN, F_REGTYPEOUT},
107 {"regrole", REGROLEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
108 F_REGROLEIN, F_REGROLEOUT},
109 {"regnamespace", REGNAMESPACEOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
110 F_REGNAMESPACEIN, F_REGNAMESPACEOUT},
111 {"text", TEXTOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
112 F_TEXTIN, F_TEXTOUT},
113 {"oid", OIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
114 F_OIDIN, F_OIDOUT},
115 {"tid", TIDOID, 0, 6, false, TYPALIGN_SHORT, TYPSTORAGE_PLAIN, InvalidOid,
116 F_TIDIN, F_TIDOUT},
117 {"xid", XIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
118 F_XIDIN, F_XIDOUT},
119 {"cid", CIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
120 F_CIDIN, F_CIDOUT},
121 {"pg_node_tree", PG_NODE_TREEOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
122 F_PG_NODE_TREE_IN, F_PG_NODE_TREE_OUT},
123 {"int2vector", INT2VECTOROID, INT2OID, -1, false, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
124 F_INT2VECTORIN, F_INT2VECTOROUT},
125 {"oidvector", OIDVECTOROID, OIDOID, -1, false, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
126 F_OIDVECTORIN, F_OIDVECTOROUT},
127 {"_int4", INT4ARRAYOID, INT4OID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
128 F_ARRAY_IN, F_ARRAY_OUT},
129 {"_text", 1009, TEXTOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
130 F_ARRAY_IN, F_ARRAY_OUT},
131 {"_oid", 1028, OIDOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
132 F_ARRAY_IN, F_ARRAY_OUT},
133 {"_char", 1002, CHAROID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
134 F_ARRAY_IN, F_ARRAY_OUT},
135 {"_aclitem", 1034, ACLITEMOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
136 F_ARRAY_IN, F_ARRAY_OUT}
139 static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);
141 struct typmap
142 { /* a hack */
143 Oid am_oid;
144 FormData_pg_type am_typ;
147 static List *Typ = NIL; /* List of struct typmap* */
148 static struct typmap *Ap = NULL;
150 static Datum values[MAXATTR]; /* current row's attribute values */
151 static bool Nulls[MAXATTR];
153 static MemoryContext nogc = NULL; /* special no-gc mem context */
156 * At bootstrap time, we first declare all the indices to be built, and
157 * then build them. The IndexList structure stores enough information
158 * to allow us to build the indices after they've been declared.
161 typedef struct _IndexList
163 Oid il_heap;
164 Oid il_ind;
165 IndexInfo *il_info;
166 struct _IndexList *il_next;
167 } IndexList;
169 static IndexList *ILHead = NULL;
173 * In shared memory checker mode, all we really want to do is create shared
174 * memory and semaphores (just to prove we can do it with the current GUC
175 * settings). Since, in fact, that was already done by
176 * CreateSharedMemoryAndSemaphores(), we have nothing more to do here.
178 static void
179 CheckerModeMain(void)
181 proc_exit(0);
185 * The main entry point for running the backend in bootstrap mode
187 * The bootstrap mode is used to initialize the template database.
188 * The bootstrap backend doesn't speak SQL, but instead expects
189 * commands in a special bootstrap language.
191 * When check_only is true, startup is done only far enough to verify that
192 * the current configuration, particularly the passed in options pertaining
193 * to shared memory sizing, options work (or at least do not cause an error
194 * up to shared memory creation).
196 void
197 BootstrapModeMain(int argc, char *argv[], bool check_only)
199 int i;
200 char *progname = argv[0];
201 int flag;
202 char *userDoption = NULL;
203 uint32 bootstrap_data_checksum_version = 0; /* No checksum */
205 Assert(!IsUnderPostmaster);
207 InitStandaloneProcess(argv[0]);
209 /* Set defaults, to be overridden by explicit options below */
210 InitializeGUCOptions();
212 /* an initial --boot or --check should be present */
213 Assert(argc > 1
214 && (strcmp(argv[1], "--boot") == 0
215 || strcmp(argv[1], "--check") == 0));
216 argv++;
217 argc--;
219 while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:X:-:")) != -1)
221 switch (flag)
223 case 'B':
224 SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
225 break;
226 case 'c':
227 case '-':
229 char *name,
230 *value;
232 ParseLongOption(optarg, &name, &value);
233 if (!value)
235 if (flag == '-')
236 ereport(ERROR,
237 (errcode(ERRCODE_SYNTAX_ERROR),
238 errmsg("--%s requires a value",
239 optarg)));
240 else
241 ereport(ERROR,
242 (errcode(ERRCODE_SYNTAX_ERROR),
243 errmsg("-c %s requires a value",
244 optarg)));
247 SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
248 pfree(name);
249 pfree(value);
250 break;
252 case 'D':
253 userDoption = pstrdup(optarg);
254 break;
255 case 'd':
257 /* Turn on debugging for the bootstrap process. */
258 char *debugstr;
260 debugstr = psprintf("debug%s", optarg);
261 SetConfigOption("log_min_messages", debugstr,
262 PGC_POSTMASTER, PGC_S_ARGV);
263 SetConfigOption("client_min_messages", debugstr,
264 PGC_POSTMASTER, PGC_S_ARGV);
265 pfree(debugstr);
267 break;
268 case 'F':
269 SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
270 break;
271 case 'k':
272 bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
273 break;
274 case 'r':
275 strlcpy(OutputFileName, optarg, MAXPGPATH);
276 break;
277 case 'X':
278 SetConfigOption("wal_segment_size", optarg, PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
279 break;
280 default:
281 write_stderr("Try \"%s --help\" for more information.\n",
282 progname);
283 proc_exit(1);
284 break;
288 if (argc != optind)
290 write_stderr("%s: invalid command-line arguments\n", progname);
291 proc_exit(1);
294 /* Acquire configuration parameters */
295 if (!SelectConfigFiles(userDoption, progname))
296 proc_exit(1);
299 * Validate we have been given a reasonable-looking DataDir and change
300 * into it
302 checkDataDir();
303 ChangeToDataDir();
305 CreateDataDirLockFile(false);
307 SetProcessingMode(BootstrapProcessing);
308 IgnoreSystemIndexes = true;
310 InitializeMaxBackends();
312 InitializeFastPathLocks();
314 CreateSharedMemoryAndSemaphores();
317 * XXX: It might make sense to move this into its own function at some
318 * point. Right now it seems like it'd cause more code duplication than
319 * it's worth.
321 if (check_only)
323 SetProcessingMode(NormalProcessing);
324 CheckerModeMain();
325 abort();
329 * Do backend-like initialization for bootstrap mode
331 InitProcess();
333 BaseInit();
335 bootstrap_signals();
336 BootStrapXLOG(bootstrap_data_checksum_version);
339 * To ensure that src/common/link-canary.c is linked into the backend, we
340 * must call it from somewhere. Here is as good as anywhere.
342 if (pg_link_canary_is_frontend())
343 elog(ERROR, "backend is incorrectly linked to frontend functions");
345 InitPostgres(NULL, InvalidOid, NULL, InvalidOid, 0, NULL);
347 /* Initialize stuff for bootstrap-file processing */
348 for (i = 0; i < MAXATTR; i++)
350 attrtypes[i] = NULL;
351 Nulls[i] = false;
355 * Process bootstrap input.
357 StartTransactionCommand();
358 boot_yyparse();
359 CommitTransactionCommand();
362 * We should now know about all mapped relations, so it's okay to write
363 * out the initial relation mapping files.
365 RelationMapFinishBootstrap();
367 /* Clean up and exit */
368 cleanup();
369 proc_exit(0);
373 /* ----------------------------------------------------------------
374 * misc functions
375 * ----------------------------------------------------------------
379 * Set up signal handling for a bootstrap process
381 static void
382 bootstrap_signals(void)
384 Assert(!IsUnderPostmaster);
387 * We don't actually need any non-default signal handling in bootstrap
388 * mode; "curl up and die" is a sufficient response for all these cases.
389 * Let's set that handling explicitly, as documentation if nothing else.
391 pqsignal(SIGHUP, SIG_DFL);
392 pqsignal(SIGINT, SIG_DFL);
393 pqsignal(SIGTERM, SIG_DFL);
394 pqsignal(SIGQUIT, SIG_DFL);
397 /* ----------------------------------------------------------------
398 * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
399 * ----------------------------------------------------------------
402 /* ----------------
403 * boot_openrel
405 * Execute BKI OPEN command.
406 * ----------------
408 void
409 boot_openrel(char *relname)
411 int i;
413 if (strlen(relname) >= NAMEDATALEN)
414 relname[NAMEDATALEN - 1] = '\0';
417 * pg_type must be filled before any OPEN command is executed, hence we
418 * can now populate Typ if we haven't yet.
420 if (Typ == NIL)
421 populate_typ_list();
423 if (boot_reldesc != NULL)
424 closerel(NULL);
426 elog(DEBUG4, "open relation %s, attrsize %d",
427 relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
429 boot_reldesc = table_openrv(makeRangeVar(NULL, relname, -1), NoLock);
430 numattr = RelationGetNumberOfAttributes(boot_reldesc);
431 for (i = 0; i < numattr; i++)
433 if (attrtypes[i] == NULL)
434 attrtypes[i] = AllocateAttribute();
435 memmove((char *) attrtypes[i],
436 (char *) TupleDescAttr(boot_reldesc->rd_att, i),
437 ATTRIBUTE_FIXED_PART_SIZE);
440 Form_pg_attribute at = attrtypes[i];
442 elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
443 i, NameStr(at->attname), at->attlen, at->attnum,
444 at->atttypid);
449 /* ----------------
450 * closerel
451 * ----------------
453 void
454 closerel(char *relname)
456 if (relname)
458 if (boot_reldesc)
460 if (strcmp(RelationGetRelationName(boot_reldesc), relname) != 0)
461 elog(ERROR, "close of %s when %s was expected",
462 relname, RelationGetRelationName(boot_reldesc));
464 else
465 elog(ERROR, "close of %s before any relation was opened",
466 relname);
469 if (boot_reldesc == NULL)
470 elog(ERROR, "no open relation to close");
471 else
473 elog(DEBUG4, "close relation %s",
474 RelationGetRelationName(boot_reldesc));
475 table_close(boot_reldesc, NoLock);
476 boot_reldesc = NULL;
482 /* ----------------
483 * DEFINEATTR()
485 * define a <field,type> pair
486 * if there are n fields in a relation to be created, this routine
487 * will be called n times
488 * ----------------
490 void
491 DefineAttr(char *name, char *type, int attnum, int nullness)
493 Oid typeoid;
495 if (boot_reldesc != NULL)
497 elog(WARNING, "no open relations allowed with CREATE command");
498 closerel(NULL);
501 if (attrtypes[attnum] == NULL)
502 attrtypes[attnum] = AllocateAttribute();
503 MemSet(attrtypes[attnum], 0, ATTRIBUTE_FIXED_PART_SIZE);
505 namestrcpy(&attrtypes[attnum]->attname, name);
506 elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
507 attrtypes[attnum]->attnum = attnum + 1;
509 typeoid = gettype(type);
511 if (Typ != NIL)
513 attrtypes[attnum]->atttypid = Ap->am_oid;
514 attrtypes[attnum]->attlen = Ap->am_typ.typlen;
515 attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
516 attrtypes[attnum]->attalign = Ap->am_typ.typalign;
517 attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
518 attrtypes[attnum]->attcompression = InvalidCompressionMethod;
519 attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
520 /* if an array type, assume 1-dimensional attribute */
521 if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
522 attrtypes[attnum]->attndims = 1;
523 else
524 attrtypes[attnum]->attndims = 0;
526 else
528 attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
529 attrtypes[attnum]->attlen = TypInfo[typeoid].len;
530 attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
531 attrtypes[attnum]->attalign = TypInfo[typeoid].align;
532 attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
533 attrtypes[attnum]->attcompression = InvalidCompressionMethod;
534 attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
535 /* if an array type, assume 1-dimensional attribute */
536 if (TypInfo[typeoid].elem != InvalidOid &&
537 attrtypes[attnum]->attlen < 0)
538 attrtypes[attnum]->attndims = 1;
539 else
540 attrtypes[attnum]->attndims = 0;
544 * If a system catalog column is collation-aware, force it to use C
545 * collation, so that its behavior is independent of the database's
546 * collation. This is essential to allow template0 to be cloned with a
547 * different database collation.
549 if (OidIsValid(attrtypes[attnum]->attcollation))
550 attrtypes[attnum]->attcollation = C_COLLATION_OID;
552 attrtypes[attnum]->attcacheoff = -1;
553 attrtypes[attnum]->atttypmod = -1;
554 attrtypes[attnum]->attislocal = true;
556 if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
558 attrtypes[attnum]->attnotnull = true;
560 else if (nullness == BOOTCOL_NULL_FORCE_NULL)
562 attrtypes[attnum]->attnotnull = false;
564 else
566 Assert(nullness == BOOTCOL_NULL_AUTO);
569 * Mark as "not null" if type is fixed-width and prior columns are
570 * likewise fixed-width and not-null. This corresponds to case where
571 * column can be accessed directly via C struct declaration.
573 if (attrtypes[attnum]->attlen > 0)
575 int i;
577 /* check earlier attributes */
578 for (i = 0; i < attnum; i++)
580 if (attrtypes[i]->attlen <= 0 ||
581 !attrtypes[i]->attnotnull)
582 break;
584 if (i == attnum)
585 attrtypes[attnum]->attnotnull = true;
591 /* ----------------
592 * InsertOneTuple
594 * If objectid is not zero, it is a specific OID to assign to the tuple.
595 * Otherwise, an OID will be assigned (if necessary) by heap_insert.
596 * ----------------
598 void
599 InsertOneTuple(void)
601 HeapTuple tuple;
602 TupleDesc tupDesc;
603 int i;
605 elog(DEBUG4, "inserting row with %d columns", numattr);
607 tupDesc = CreateTupleDesc(numattr, attrtypes);
608 tuple = heap_form_tuple(tupDesc, values, Nulls);
609 pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
611 simple_heap_insert(boot_reldesc, tuple);
612 heap_freetuple(tuple);
613 elog(DEBUG4, "row inserted");
616 * Reset null markers for next tuple
618 for (i = 0; i < numattr; i++)
619 Nulls[i] = false;
622 /* ----------------
623 * InsertOneValue
624 * ----------------
626 void
627 InsertOneValue(char *value, int i)
629 Oid typoid;
630 int16 typlen;
631 bool typbyval;
632 char typalign;
633 char typdelim;
634 Oid typioparam;
635 Oid typinput;
636 Oid typoutput;
638 Assert(i >= 0 && i < MAXATTR);
640 elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
642 typoid = TupleDescAttr(boot_reldesc->rd_att, i)->atttypid;
644 boot_get_type_io_data(typoid,
645 &typlen, &typbyval, &typalign,
646 &typdelim, &typioparam,
647 &typinput, &typoutput);
649 values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
652 * We use ereport not elog here so that parameters aren't evaluated unless
653 * the message is going to be printed, which generally it isn't
655 ereport(DEBUG4,
656 (errmsg_internal("inserted -> %s",
657 OidOutputFunctionCall(typoutput, values[i]))));
660 /* ----------------
661 * InsertOneNull
662 * ----------------
664 void
665 InsertOneNull(int i)
667 elog(DEBUG4, "inserting column %d NULL", i);
668 Assert(i >= 0 && i < MAXATTR);
669 if (TupleDescAttr(boot_reldesc->rd_att, i)->attnotnull)
670 elog(ERROR,
671 "NULL value specified for not-null column \"%s\" of relation \"%s\"",
672 NameStr(TupleDescAttr(boot_reldesc->rd_att, i)->attname),
673 RelationGetRelationName(boot_reldesc));
674 values[i] = PointerGetDatum(NULL);
675 Nulls[i] = true;
678 /* ----------------
679 * cleanup
680 * ----------------
682 static void
683 cleanup(void)
685 if (boot_reldesc != NULL)
686 closerel(NULL);
689 /* ----------------
690 * populate_typ_list
692 * Load the Typ list by reading pg_type.
693 * ----------------
695 static void
696 populate_typ_list(void)
698 Relation rel;
699 TableScanDesc scan;
700 HeapTuple tup;
701 MemoryContext old;
703 Assert(Typ == NIL);
705 rel = table_open(TypeRelationId, NoLock);
706 scan = table_beginscan_catalog(rel, 0, NULL);
707 old = MemoryContextSwitchTo(TopMemoryContext);
708 while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
710 Form_pg_type typForm = (Form_pg_type) GETSTRUCT(tup);
711 struct typmap *newtyp;
713 newtyp = (struct typmap *) palloc(sizeof(struct typmap));
714 Typ = lappend(Typ, newtyp);
716 newtyp->am_oid = typForm->oid;
717 memcpy(&newtyp->am_typ, typForm, sizeof(newtyp->am_typ));
719 MemoryContextSwitchTo(old);
720 table_endscan(scan);
721 table_close(rel, NoLock);
724 /* ----------------
725 * gettype
727 * NB: this is really ugly; it will return an integer index into TypInfo[],
728 * and not an OID at all, until the first reference to a type not known in
729 * TypInfo[]. At that point it will read and cache pg_type in Typ,
730 * and subsequently return a real OID (and set the global pointer Ap to
731 * point at the found row in Typ). So caller must check whether Typ is
732 * still NIL to determine what the return value is!
733 * ----------------
735 static Oid
736 gettype(char *type)
738 if (Typ != NIL)
740 ListCell *lc;
742 foreach(lc, Typ)
744 struct typmap *app = lfirst(lc);
746 if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
748 Ap = app;
749 return app->am_oid;
754 * The type wasn't known; reload the pg_type contents and check again
755 * to handle composite types, added since last populating the list.
758 list_free_deep(Typ);
759 Typ = NIL;
760 populate_typ_list();
763 * Calling gettype would result in infinite recursion for types
764 * missing in pg_type, so just repeat the lookup.
766 foreach(lc, Typ)
768 struct typmap *app = lfirst(lc);
770 if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
772 Ap = app;
773 return app->am_oid;
777 else
779 int i;
781 for (i = 0; i < n_types; i++)
783 if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
784 return i;
786 /* Not in TypInfo, so we'd better be able to read pg_type now */
787 elog(DEBUG4, "external type: %s", type);
788 populate_typ_list();
789 return gettype(type);
791 elog(ERROR, "unrecognized type \"%s\"", type);
792 /* not reached, here to make compiler happy */
793 return 0;
796 /* ----------------
797 * boot_get_type_io_data
799 * Obtain type I/O information at bootstrap time. This intentionally has
800 * almost the same API as lsyscache.c's get_type_io_data, except that
801 * we only support obtaining the typinput and typoutput routines, not
802 * the binary I/O routines. It is exported so that array_in and array_out
803 * can be made to work during early bootstrap.
804 * ----------------
806 void
807 boot_get_type_io_data(Oid typid,
808 int16 *typlen,
809 bool *typbyval,
810 char *typalign,
811 char *typdelim,
812 Oid *typioparam,
813 Oid *typinput,
814 Oid *typoutput)
816 if (Typ != NIL)
818 /* We have the boot-time contents of pg_type, so use it */
819 struct typmap *ap = NULL;
820 ListCell *lc;
822 foreach(lc, Typ)
824 ap = lfirst(lc);
825 if (ap->am_oid == typid)
826 break;
829 if (!ap || ap->am_oid != typid)
830 elog(ERROR, "type OID %u not found in Typ list", typid);
832 *typlen = ap->am_typ.typlen;
833 *typbyval = ap->am_typ.typbyval;
834 *typalign = ap->am_typ.typalign;
835 *typdelim = ap->am_typ.typdelim;
837 /* XXX this logic must match getTypeIOParam() */
838 if (OidIsValid(ap->am_typ.typelem))
839 *typioparam = ap->am_typ.typelem;
840 else
841 *typioparam = typid;
843 *typinput = ap->am_typ.typinput;
844 *typoutput = ap->am_typ.typoutput;
846 else
848 /* We don't have pg_type yet, so use the hard-wired TypInfo array */
849 int typeindex;
851 for (typeindex = 0; typeindex < n_types; typeindex++)
853 if (TypInfo[typeindex].oid == typid)
854 break;
856 if (typeindex >= n_types)
857 elog(ERROR, "type OID %u not found in TypInfo", typid);
859 *typlen = TypInfo[typeindex].len;
860 *typbyval = TypInfo[typeindex].byval;
861 *typalign = TypInfo[typeindex].align;
862 /* We assume typdelim is ',' for all boot-time types */
863 *typdelim = ',';
865 /* XXX this logic must match getTypeIOParam() */
866 if (OidIsValid(TypInfo[typeindex].elem))
867 *typioparam = TypInfo[typeindex].elem;
868 else
869 *typioparam = typid;
871 *typinput = TypInfo[typeindex].inproc;
872 *typoutput = TypInfo[typeindex].outproc;
876 /* ----------------
877 * AllocateAttribute
879 * Note: bootstrap never sets any per-column ACLs, so we only need
880 * ATTRIBUTE_FIXED_PART_SIZE space per attribute.
881 * ----------------
883 static Form_pg_attribute
884 AllocateAttribute(void)
886 return (Form_pg_attribute)
887 MemoryContextAllocZero(TopMemoryContext, ATTRIBUTE_FIXED_PART_SIZE);
891 * index_register() -- record an index that has been set up for building
892 * later.
894 * At bootstrap time, we define a bunch of indexes on system catalogs.
895 * We postpone actually building the indexes until just before we're
896 * finished with initialization, however. This is because the indexes
897 * themselves have catalog entries, and those have to be included in the
898 * indexes on those catalogs. Doing it in two phases is the simplest
899 * way of making sure the indexes have the right contents at the end.
901 void
902 index_register(Oid heap,
903 Oid ind,
904 const IndexInfo *indexInfo)
906 IndexList *newind;
907 MemoryContext oldcxt;
910 * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
911 * bootstrap time. we'll declare the indexes now, but want to create them
912 * later.
915 if (nogc == NULL)
916 nogc = AllocSetContextCreate(NULL,
917 "BootstrapNoGC",
918 ALLOCSET_DEFAULT_SIZES);
920 oldcxt = MemoryContextSwitchTo(nogc);
922 newind = (IndexList *) palloc(sizeof(IndexList));
923 newind->il_heap = heap;
924 newind->il_ind = ind;
925 newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
927 memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
928 /* expressions will likely be null, but may as well copy it */
929 newind->il_info->ii_Expressions =
930 copyObject(indexInfo->ii_Expressions);
931 newind->il_info->ii_ExpressionsState = NIL;
932 /* predicate will likely be null, but may as well copy it */
933 newind->il_info->ii_Predicate =
934 copyObject(indexInfo->ii_Predicate);
935 newind->il_info->ii_PredicateState = NULL;
936 /* no exclusion constraints at bootstrap time, so no need to copy */
937 Assert(indexInfo->ii_ExclusionOps == NULL);
938 Assert(indexInfo->ii_ExclusionProcs == NULL);
939 Assert(indexInfo->ii_ExclusionStrats == NULL);
941 newind->il_next = ILHead;
942 ILHead = newind;
944 MemoryContextSwitchTo(oldcxt);
949 * build_indices -- fill in all the indexes registered earlier
951 void
952 build_indices(void)
954 for (; ILHead != NULL; ILHead = ILHead->il_next)
956 Relation heap;
957 Relation ind;
959 /* need not bother with locks during bootstrap */
960 heap = table_open(ILHead->il_heap, NoLock);
961 ind = index_open(ILHead->il_ind, NoLock);
963 index_build(heap, ind, ILHead->il_info, false, false);
965 index_close(ind, NoLock);
966 table_close(heap, NoLock);