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