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-2026, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/bootstrap/bootstrap.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include <unistd.h>
18 : : #include <signal.h>
19 : :
20 : : #include "access/genam.h"
21 : : #include "access/heapam.h"
22 : : #include "access/htup_details.h"
23 : : #include "access/tableam.h"
24 : : #include "access/toast_compression.h"
25 : : #include "access/xact.h"
26 : : #include "bootstrap/bootstrap.h"
27 : : #include "catalog/index.h"
28 : : #include "catalog/pg_authid.h"
29 : : #include "catalog/pg_collation.h"
30 : : #include "catalog/pg_proc.h"
31 : : #include "catalog/pg_type.h"
32 : : #include "common/link-canary.h"
33 : : #include "miscadmin.h"
34 : : #include "nodes/makefuncs.h"
35 : : #include "pg_getopt.h"
36 : : #include "postmaster/postmaster.h"
37 : : #include "storage/bufpage.h"
38 : : #include "storage/ipc.h"
39 : : #include "storage/proc.h"
40 : : #include "utils/builtins.h"
41 : : #include "utils/fmgroids.h"
42 : : #include "utils/guc.h"
43 : : #include "utils/memutils.h"
44 : : #include "utils/rel.h"
45 : : #include "utils/relmapper.h"
46 : :
47 : :
48 : : static void CheckerModeMain(void);
49 : : static void bootstrap_signals(void);
50 : : static Form_pg_attribute AllocateAttribute(void);
51 : : static void InsertOneProargdefaultsValue(char *value);
52 : : static void populate_typ_list(void);
53 : : static Oid gettype(char *type);
54 : : static void cleanup(void);
55 : :
56 : : /* ----------------
57 : : * global variables
58 : : * ----------------
59 : : */
60 : :
61 : : Relation boot_reldesc; /* current relation descriptor */
62 : :
63 : : Form_pg_attribute attrtypes[MAXATTR]; /* points to attribute info */
64 : : int numattr; /* number of attributes for cur. rel */
65 : :
66 : :
67 : : /*
68 : : * Basic information associated with each type. This is used before
69 : : * pg_type is filled, so it has to cover the datatypes used as column types
70 : : * in the core "bootstrapped" catalogs.
71 : : *
72 : : * XXX several of these input/output functions do catalog scans
73 : : * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some
74 : : * order dependencies in the catalog creation process.
75 : : */
76 : : struct typinfo
77 : : {
78 : : char name[NAMEDATALEN];
79 : : Oid oid;
80 : : Oid elem;
81 : : int16 len;
82 : : bool byval;
83 : : char align;
84 : : char storage;
85 : : Oid collation;
86 : : Oid inproc;
87 : : Oid outproc;
88 : : };
89 : :
90 : : static const struct typinfo TypInfo[] = {
91 : : {"bool", BOOLOID, 0, 1, true, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
92 : : F_BOOLIN, F_BOOLOUT},
93 : : {"bytea", BYTEAOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
94 : : F_BYTEAIN, F_BYTEAOUT},
95 : : {"char", CHAROID, 0, 1, true, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
96 : : F_CHARIN, F_CHAROUT},
97 : : {"cstring", CSTRINGOID, 0, -2, false, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, InvalidOid,
98 : : F_CSTRING_IN, F_CSTRING_OUT},
99 : : {"int2", INT2OID, 0, 2, true, TYPALIGN_SHORT, TYPSTORAGE_PLAIN, InvalidOid,
100 : : F_INT2IN, F_INT2OUT},
101 : : {"int4", INT4OID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
102 : : F_INT4IN, F_INT4OUT},
103 : : {"int8", INT8OID, 0, 8, true, TYPALIGN_DOUBLE, TYPSTORAGE_PLAIN, InvalidOid,
104 : : F_INT8IN, F_INT8OUT},
105 : : {"float4", FLOAT4OID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
106 : : F_FLOAT4IN, F_FLOAT4OUT},
107 : : {"float8", FLOAT8OID, 0, 8, true, TYPALIGN_DOUBLE, TYPSTORAGE_PLAIN, InvalidOid,
108 : : F_FLOAT8IN, F_FLOAT8OUT},
109 : : {"name", NAMEOID, CHAROID, NAMEDATALEN, false, TYPALIGN_CHAR, TYPSTORAGE_PLAIN, C_COLLATION_OID,
110 : : F_NAMEIN, F_NAMEOUT},
111 : : {"regproc", REGPROCOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
112 : : F_REGPROCIN, F_REGPROCOUT},
113 : : {"text", TEXTOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
114 : : F_TEXTIN, F_TEXTOUT},
115 : : {"jsonb", JSONBOID, 0, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
116 : : F_JSONB_IN, F_JSONB_OUT},
117 : : {"oid", OIDOID, 0, 4, true, TYPALIGN_INT, TYPSTORAGE_PLAIN, InvalidOid,
118 : : F_OIDIN, F_OIDOUT},
119 : : {"aclitem", ACLITEMOID, 0, 16, false, TYPALIGN_DOUBLE, TYPSTORAGE_PLAIN, InvalidOid,
120 : : F_ACLITEMIN, F_ACLITEMOUT},
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", TEXTARRAYOID, TEXTOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, DEFAULT_COLLATION_OID,
130 : : F_ARRAY_IN, F_ARRAY_OUT},
131 : : {"_oid", OIDARRAYOID, OIDOID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
132 : : F_ARRAY_IN, F_ARRAY_OUT},
133 : : {"_char", CHARARRAYOID, CHAROID, -1, false, TYPALIGN_INT, TYPSTORAGE_EXTENDED, InvalidOid,
134 : : F_ARRAY_IN, F_ARRAY_OUT},
135 : : {"_aclitem", ACLITEMARRAYOID, ACLITEMOID, -1, false, TYPALIGN_DOUBLE, TYPSTORAGE_EXTENDED, InvalidOid,
136 : : F_ARRAY_IN, F_ARRAY_OUT}
137 : : };
138 : :
139 : : static const int n_types = sizeof(TypInfo) / sizeof(struct typinfo);
140 : :
141 : : struct typmap
142 : : { /* a hack */
143 : : Oid am_oid;
144 : : FormData_pg_type am_typ;
145 : : };
146 : :
147 : : static List *Typ = NIL; /* List of struct typmap* */
148 : : static struct typmap *Ap = NULL;
149 : :
150 : : /*
151 : : * Basic information about built-in roles.
152 : : *
153 : : * Presently, this need only list roles that are mentioned in aclitem arrays
154 : : * in the catalog .dat files. We might as well list everything that is in
155 : : * pg_authid.dat, since there aren't that many. Like pg_authid.dat, we
156 : : * represent the bootstrap superuser's name as "POSTGRES", even though it
157 : : * (probably) won't be that in the finished installation; this means aclitem
158 : : * entries in .dat files must spell it like that.
159 : : */
160 : : struct rolinfo
161 : : {
162 : : const char *rolname;
163 : : Oid oid;
164 : : };
165 : :
166 : : static const struct rolinfo RolInfo[] = {
167 : : {"POSTGRES", BOOTSTRAP_SUPERUSERID},
168 : : {"pg_database_owner", ROLE_PG_DATABASE_OWNER},
169 : : {"pg_read_all_data", ROLE_PG_READ_ALL_DATA},
170 : : {"pg_write_all_data", ROLE_PG_WRITE_ALL_DATA},
171 : : {"pg_monitor", ROLE_PG_MONITOR},
172 : : {"pg_read_all_settings", ROLE_PG_READ_ALL_SETTINGS},
173 : : {"pg_read_all_stats", ROLE_PG_READ_ALL_STATS},
174 : : {"pg_stat_scan_tables", ROLE_PG_STAT_SCAN_TABLES},
175 : : {"pg_read_server_files", ROLE_PG_READ_SERVER_FILES},
176 : : {"pg_write_server_files", ROLE_PG_WRITE_SERVER_FILES},
177 : : {"pg_execute_server_program", ROLE_PG_EXECUTE_SERVER_PROGRAM},
178 : : {"pg_signal_backend", ROLE_PG_SIGNAL_BACKEND},
179 : : {"pg_checkpoint", ROLE_PG_CHECKPOINT},
180 : : {"pg_maintain", ROLE_PG_MAINTAIN},
181 : : {"pg_use_reserved_connections", ROLE_PG_USE_RESERVED_CONNECTIONS},
182 : : {"pg_create_subscription", ROLE_PG_CREATE_SUBSCRIPTION},
183 : : {"pg_signal_autovacuum_worker", ROLE_PG_SIGNAL_AUTOVACUUM_WORKER}
184 : : };
185 : :
186 : :
187 : : static Datum values[MAXATTR]; /* current row's attribute values */
188 : : static bool Nulls[MAXATTR];
189 : :
190 : : static MemoryContext nogc = NULL; /* special no-gc mem context */
191 : :
192 : : /*
193 : : * At bootstrap time, we first declare all the indices to be built, and
194 : : * then build them. The IndexList structure stores enough information
195 : : * to allow us to build the indices after they've been declared.
196 : : */
197 : :
198 : : typedef struct _IndexList
199 : : {
200 : : Oid il_heap;
201 : : Oid il_ind;
202 : : IndexInfo *il_info;
203 : : struct _IndexList *il_next;
204 : : } IndexList;
205 : :
206 : : static IndexList *ILHead = NULL;
207 : :
208 : :
209 : : /*
210 : : * In shared memory checker mode, all we really want to do is create shared
211 : : * memory and semaphores (just to prove we can do it with the current GUC
212 : : * settings). Since, in fact, that was already done by
213 : : * CreateSharedMemoryAndSemaphores(), we have nothing more to do here.
214 : : */
215 : : static void
6948 alvherre@alvh.no-ip. 216 :CBC 102 : CheckerModeMain(void)
217 : : {
218 : 102 : proc_exit(0);
219 : : }
220 : :
221 : : /*
222 : : * The main entry point for running the backend in bootstrap mode
223 : : *
224 : : * The bootstrap mode is used to initialize the template database.
225 : : * The bootstrap backend doesn't speak SQL, but instead expects
226 : : * commands in a special bootstrap language.
227 : : *
228 : : * When check_only is true, startup is done only far enough to verify that
229 : : * the current configuration, particularly the passed in options pertaining
230 : : * to shared memory sizing, options work (or at least do not cause an error
231 : : * up to shared memory creation).
232 : : */
233 : : void
1683 andres@anarazel.de 234 : 178 : BootstrapModeMain(int argc, char *argv[], bool check_only)
235 : : {
236 : : int i;
1684 237 : 178 : char *progname = argv[0];
238 : : int flag;
239 : 178 : char *userDoption = NULL;
600 peter@eisentraut.org 240 : 178 : uint32 bootstrap_data_checksum_version = 0; /* No checksum */
241 : : yyscan_t scanner;
242 : :
6948 alvherre@alvh.no-ip. 243 [ - + ]: 178 : Assert(!IsUnderPostmaster);
244 : :
1684 andres@anarazel.de 245 : 178 : InitStandaloneProcess(argv[0]);
246 : :
247 : : /* Set defaults, to be overridden by explicit options below */
248 : 178 : InitializeGUCOptions();
249 : :
250 : : /* an initial --boot or --check should be present */
1679 251 [ + - + + : 178 : Assert(argc > 1
- + ]
252 : : && (strcmp(argv[1], "--boot") == 0
253 : : || strcmp(argv[1], "--check") == 0));
1684 254 : 178 : argv++;
255 : 178 : argc--;
256 : :
1683 257 [ + + ]: 1152 : while ((flag = getopt(argc, argv, "B:c:d:D:Fkr:X:-:")) != -1)
258 : : {
1684 259 [ - - + - : 998 : switch (flag)
- + + - +
- ]
260 : : {
1684 andres@anarazel.de 261 :UBC 0 : case 'B':
262 : 0 : SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
263 : 0 : break;
1189 peter@eisentraut.org 264 : 0 : case '-':
265 : :
266 : : /*
267 : : * Error if the user misplaced a special must-be-first option
268 : : * for dispatching to a subprogram. parse_dispatch_option()
269 : : * returns DISPATCH_POSTMASTER if it doesn't find a match, so
270 : : * error for anything else.
271 : : */
466 nathan@postgresql.or 272 [ # # ]: 0 : if (parse_dispatch_option(optarg) != DISPATCH_POSTMASTER)
273 [ # # ]: 0 : ereport(ERROR,
274 : : (errcode(ERRCODE_SYNTAX_ERROR),
275 : : errmsg("--%s must be first argument", optarg)));
276 : :
277 : : pg_fallthrough;
278 : : case 'c':
279 : : {
280 : : char *name,
281 : : *value;
282 : :
1189 peter@eisentraut.org 283 :CBC 722 : ParseLongOption(optarg, &name, &value);
284 [ - + ]: 722 : if (!value)
285 : : {
1189 peter@eisentraut.org 286 [ # # ]:UBC 0 : if (flag == '-')
287 [ # # ]: 0 : ereport(ERROR,
288 : : (errcode(ERRCODE_SYNTAX_ERROR),
289 : : errmsg("--%s requires a value",
290 : : optarg)));
291 : : else
292 [ # # ]: 0 : ereport(ERROR,
293 : : (errcode(ERRCODE_SYNTAX_ERROR),
294 : : errmsg("-c %s requires a value",
295 : : optarg)));
296 : : }
297 : :
1189 peter@eisentraut.org 298 :CBC 722 : SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
299 : 698 : pfree(name);
300 : 698 : pfree(value);
301 : 698 : break;
302 : : }
1684 andres@anarazel.de 303 :UBC 0 : case 'D':
304 : 0 : userDoption = pstrdup(optarg);
305 : 0 : break;
306 : 0 : case 'd':
307 : : {
308 : : /* Turn on debugging for the bootstrap process. */
309 : : char *debugstr;
310 : :
311 : 0 : debugstr = psprintf("debug%s", optarg);
312 : 0 : SetConfigOption("log_min_messages", debugstr,
313 : : PGC_POSTMASTER, PGC_S_ARGV);
314 : 0 : SetConfigOption("client_min_messages", debugstr,
315 : : PGC_POSTMASTER, PGC_S_ARGV);
316 : 0 : pfree(debugstr);
317 : : }
318 : 0 : break;
1684 andres@anarazel.de 319 :CBC 178 : case 'F':
320 : 178 : SetConfigOption("fsync", "false", PGC_POSTMASTER, PGC_S_ARGV);
321 : 178 : break;
322 : 46 : case 'k':
323 : 46 : bootstrap_data_checksum_version = PG_DATA_CHECKSUM_VERSION;
324 : 46 : break;
1684 andres@anarazel.de 325 :UBC 0 : case 'r':
326 : 0 : strlcpy(OutputFileName, optarg, MAXPGPATH);
327 : 0 : break;
1684 andres@anarazel.de 328 :CBC 52 : case 'X':
930 peter@eisentraut.org 329 : 52 : SetConfigOption("wal_segment_size", optarg, PGC_INTERNAL, PGC_S_DYNAMIC_DEFAULT);
1684 andres@anarazel.de 330 : 52 : break;
1684 andres@anarazel.de 331 :UBC 0 : default:
332 : 0 : write_stderr("Try \"%s --help\" for more information.\n",
333 : : progname);
334 : 0 : proc_exit(1);
335 : : break;
336 : : }
337 : : }
338 : :
1684 andres@anarazel.de 339 [ - + ]:CBC 154 : if (argc != optind)
340 : : {
1684 andres@anarazel.de 341 :UBC 0 : write_stderr("%s: invalid command-line arguments\n", progname);
342 : 0 : proc_exit(1);
343 : : }
344 : :
345 : : /* Acquire configuration parameters */
1684 andres@anarazel.de 346 [ - + ]:CBC 154 : if (!SelectConfigFiles(userDoption, progname))
1684 andres@anarazel.de 347 :UBC 0 : proc_exit(1);
348 : :
349 : : /*
350 : : * Validate we have been given a reasonable-looking DataDir and change
351 : : * into it
352 : : */
1684 andres@anarazel.de 353 :CBC 153 : checkDataDir();
354 : 153 : ChangeToDataDir();
355 : :
356 : 153 : CreateDataDirLockFile(false);
357 : :
358 : 153 : SetProcessingMode(BootstrapProcessing);
359 : 153 : IgnoreSystemIndexes = true;
360 : :
361 : 153 : InitializeMaxBackends();
362 : :
363 : : /*
364 : : * Even though bootstrapping runs in single-process mode, initialize
365 : : * postmaster child slots array so that --check can detect running out of
366 : : * shared memory or other resources if max_connections is set too high.
367 : : */
486 heikki.linnakangas@i 368 : 153 : InitPostmasterChildSlots();
369 : :
540 tomas.vondra@postgre 370 : 153 : InitializeFastPathLocks();
371 : :
1683 andres@anarazel.de 372 : 153 : CreateSharedMemoryAndSemaphores();
373 : :
374 : : /*
375 : : * Estimate number of openable files. This is essential too in --check
376 : : * mode, because on some platforms semaphores count as open files.
377 : : */
453 tgl@sss.pgh.pa.us 378 : 153 : set_max_safe_fds();
379 : :
380 : : /*
381 : : * XXX: It might make sense to move this into its own function at some
382 : : * point. Right now it seems like it'd cause more code duplication than
383 : : * it's worth.
384 : : */
1683 andres@anarazel.de 385 [ + + ]: 153 : if (check_only)
386 : : {
1684 387 : 102 : SetProcessingMode(NormalProcessing);
388 : 102 : CheckerModeMain();
1684 andres@anarazel.de 389 :UBC 0 : abort();
390 : : }
391 : :
392 : : /*
393 : : * Do backend-like initialization for bootstrap mode
394 : : */
1683 andres@anarazel.de 395 :CBC 51 : InitProcess();
396 : :
397 : 51 : BaseInit();
398 : :
1684 399 : 51 : bootstrap_signals();
600 peter@eisentraut.org 400 : 51 : BootStrapXLOG(bootstrap_data_checksum_version);
401 : :
402 : : /*
403 : : * To ensure that src/common/link-canary.c is linked into the backend, we
404 : : * must call it from somewhere. Here is as good as anywhere.
405 : : */
2744 tgl@sss.pgh.pa.us 406 [ - + ]: 51 : if (pg_link_canary_is_frontend())
2744 tgl@sss.pgh.pa.us 407 [ # # ]:UBC 0 : elog(ERROR, "backend is incorrectly linked to frontend functions");
408 : :
886 michael@paquier.xyz 409 :CBC 51 : InitPostgres(NULL, InvalidOid, NULL, InvalidOid, 0, NULL);
410 : :
411 : : /* Initialize stuff for bootstrap-file processing */
10416 bruce@momjian.us 412 [ + + ]: 2091 : for (i = 0; i < MAXATTR; i++)
413 : : {
8103 neilc@samurai.com 414 : 2040 : attrtypes[i] = NULL;
6342 tgl@sss.pgh.pa.us 415 : 2040 : Nulls[i] = false;
416 : : }
417 : :
451 peter@eisentraut.org 418 [ - + ]: 51 : if (boot_yylex_init(&scanner) != 0)
451 peter@eisentraut.org 419 [ # # ]:UBC 0 : elog(ERROR, "yylex_init() failed: %m");
420 : :
421 : : /*
422 : : * Process bootstrap input.
423 : : */
3257 tgl@sss.pgh.pa.us 424 :CBC 51 : StartTransactionCommand();
451 peter@eisentraut.org 425 : 51 : boot_yyparse(scanner);
3257 tgl@sss.pgh.pa.us 426 : 51 : CommitTransactionCommand();
427 : :
428 : : /*
429 : : * We should now know about all mapped relations, so it's okay to write
430 : : * out the initial relation mapping files.
431 : : */
5880 432 : 51 : RelationMapFinishBootstrap();
433 : :
434 : : /* Clean up and exit */
10416 bruce@momjian.us 435 : 51 : cleanup();
6948 alvherre@alvh.no-ip. 436 : 51 : proc_exit(0);
437 : : }
438 : :
439 : :
440 : : /* ----------------------------------------------------------------
441 : : * misc functions
442 : : * ----------------------------------------------------------------
443 : : */
444 : :
445 : : /*
446 : : * Set up signal handling for a bootstrap process
447 : : */
448 : : static void
7960 tgl@sss.pgh.pa.us 449 : 51 : bootstrap_signals(void)
450 : : {
4079 andres@anarazel.de 451 [ - + ]: 51 : Assert(!IsUnderPostmaster);
452 : :
453 : : /*
454 : : * We don't actually need any non-default signal handling in bootstrap
455 : : * mode; "curl up and die" is a sufficient response for all these cases.
456 : : * Let's set that handling explicitly, as documentation if nothing else.
457 : : */
2497 tgl@sss.pgh.pa.us 458 : 51 : pqsignal(SIGHUP, SIG_DFL);
459 : 51 : pqsignal(SIGINT, SIG_DFL);
460 : 51 : pqsignal(SIGTERM, SIG_DFL);
461 : 51 : pqsignal(SIGQUIT, SIG_DFL);
7960 462 : 51 : }
463 : :
464 : : /* ----------------------------------------------------------------
465 : : * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
466 : : * ----------------------------------------------------------------
467 : : */
468 : :
469 : : /* ----------------
470 : : * boot_openrel
471 : : *
472 : : * Execute BKI OPEN command.
473 : : * ----------------
474 : : */
475 : : void
10841 scrappy@hub.org 476 : 3060 : boot_openrel(char *relname)
477 : : {
478 : : int i;
479 : :
7640 tgl@sss.pgh.pa.us 480 [ - + ]: 3060 : if (strlen(relname) >= NAMEDATALEN)
10244 bruce@momjian.us 481 :UBC 0 : relname[NAMEDATALEN - 1] = '\0';
482 : :
483 : : /*
484 : : * pg_type must be filled before any OPEN command is executed, hence we
485 : : * can now populate Typ if we haven't yet.
486 : : */
1817 tomas.vondra@postgre 487 [ - + ]:CBC 3060 : if (Typ == NIL)
1817 tomas.vondra@postgre 488 :UBC 0 : populate_typ_list();
489 : :
8723 tgl@sss.pgh.pa.us 490 [ - + ]:CBC 3060 : if (boot_reldesc != NULL)
10416 bruce@momjian.us 491 :UBC 0 : closerel(NULL);
492 : :
8272 tgl@sss.pgh.pa.us 493 [ - + ]:CBC 3060 : elog(DEBUG4, "open relation %s, attrsize %d",
494 : : relname, (int) ATTRIBUTE_FIXED_PART_SIZE);
495 : :
2610 andres@anarazel.de 496 : 3060 : boot_reldesc = table_openrv(makeRangeVar(NULL, relname, -1), NoLock);
2899 teodor@sigaev.ru 497 : 3060 : numattr = RelationGetNumberOfAttributes(boot_reldesc);
10416 bruce@momjian.us 498 [ + + ]: 28203 : for (i = 0; i < numattr; i++)
499 : : {
500 [ - + ]: 25143 : if (attrtypes[i] == NULL)
10416 bruce@momjian.us 501 :UBC 0 : attrtypes[i] = AllocateAttribute();
396 peter@eisentraut.org 502 :CBC 25143 : memmove(attrtypes[i],
503 : 25143 : TupleDescAttr(boot_reldesc->rd_att, i),
504 : : ATTRIBUTE_FIXED_PART_SIZE);
505 : :
506 : : {
10057 bruce@momjian.us 507 : 25143 : Form_pg_attribute at = attrtypes[i];
508 : :
8328 509 [ - + ]: 25143 : elog(DEBUG4, "create attribute %d name %s len %d num %d type %u",
510 : : i, NameStr(at->attname), at->attlen, at->attnum,
511 : : at->atttypid);
512 : : }
513 : : }
10841 scrappy@hub.org 514 : 3060 : }
515 : :
516 : : /* ----------------
517 : : * closerel
518 : : * ----------------
519 : : */
520 : : void
1272 pg@bowt.ie 521 : 3264 : closerel(char *relname)
522 : : {
523 [ + - ]: 3264 : if (relname)
524 : : {
8723 tgl@sss.pgh.pa.us 525 [ + - ]: 3264 : if (boot_reldesc)
526 : : {
1272 pg@bowt.ie 527 [ - + ]: 3264 : if (strcmp(RelationGetRelationName(boot_reldesc), relname) != 0)
8272 tgl@sss.pgh.pa.us 528 [ # # ]:UBC 0 : elog(ERROR, "close of %s when %s was expected",
529 : : relname, RelationGetRelationName(boot_reldesc));
530 : : }
531 : : else
532 [ # # ]: 0 : elog(ERROR, "close of %s before any relation was opened",
533 : : relname);
534 : : }
535 : :
8723 tgl@sss.pgh.pa.us 536 [ - + ]:CBC 3264 : if (boot_reldesc == NULL)
9073 peter_e@gmx.net 537 [ # # ]:UBC 0 : elog(ERROR, "no open relation to close");
538 : : else
539 : : {
7640 tgl@sss.pgh.pa.us 540 [ - + ]:CBC 3264 : elog(DEBUG4, "close relation %s",
541 : : RelationGetRelationName(boot_reldesc));
2610 andres@anarazel.de 542 : 3264 : table_close(boot_reldesc, NoLock);
8103 neilc@samurai.com 543 : 3264 : boot_reldesc = NULL;
544 : : }
10841 scrappy@hub.org 545 : 3264 : }
546 : :
547 : :
548 : :
549 : : /* ----------------
550 : : * DEFINEATTR()
551 : : *
552 : : * define a <field,type> pair
553 : : * if there are n fields in a relation to be created, this routine
554 : : * will be called n times
555 : : * ----------------
556 : : */
557 : : void
4040 andres@anarazel.de 558 : 31314 : DefineAttr(char *name, char *type, int attnum, int nullness)
559 : : {
560 : : Oid typeoid;
561 : :
8723 tgl@sss.pgh.pa.us 562 [ - + ]: 31314 : if (boot_reldesc != NULL)
563 : : {
8272 tgl@sss.pgh.pa.us 564 [ # # ]:UBC 0 : elog(WARNING, "no open relations allowed with CREATE command");
7640 565 : 0 : closerel(NULL);
566 : : }
567 : :
8103 neilc@samurai.com 568 [ + + ]:CBC 31314 : if (attrtypes[attnum] == NULL)
10416 bruce@momjian.us 569 : 1734 : attrtypes[attnum] = AllocateAttribute();
6261 tgl@sss.pgh.pa.us 570 [ + - - + : 31314 : MemSet(attrtypes[attnum], 0, ATTRIBUTE_FIXED_PART_SIZE);
- - - - -
- ]
571 : :
8626 572 : 31314 : namestrcpy(&attrtypes[attnum]->attname, name);
8328 bruce@momjian.us 573 [ - + ]: 31314 : elog(DEBUG4, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
2434 michael@paquier.xyz 574 : 31314 : attrtypes[attnum]->attnum = attnum + 1;
575 : :
8626 tgl@sss.pgh.pa.us 576 : 31314 : typeoid = gettype(type);
577 : :
1817 tomas.vondra@postgre 578 [ + + ]: 31314 : if (Typ != NIL)
579 : : {
10416 bruce@momjian.us 580 : 26928 : attrtypes[attnum]->atttypid = Ap->am_oid;
7656 tgl@sss.pgh.pa.us 581 : 26928 : attrtypes[attnum]->attlen = Ap->am_typ.typlen;
10416 bruce@momjian.us 582 : 26928 : attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
10065 583 : 26928 : attrtypes[attnum]->attalign = Ap->am_typ.typalign;
1757 tgl@sss.pgh.pa.us 584 : 26928 : attrtypes[attnum]->attstorage = Ap->am_typ.typstorage;
1753 585 : 26928 : attrtypes[attnum]->attcompression = InvalidCompressionMethod;
5514 peter_e@gmx.net 586 : 26928 : attrtypes[attnum]->attcollation = Ap->am_typ.typcollation;
587 : : /* if an array type, assume 1-dimensional attribute */
8104 tgl@sss.pgh.pa.us 588 [ + + + + ]: 26928 : if (Ap->am_typ.typelem != InvalidOid && Ap->am_typ.typlen < 0)
589 : 2397 : attrtypes[attnum]->attndims = 1;
590 : : else
591 : 24531 : attrtypes[attnum]->attndims = 0;
592 : : }
593 : : else
594 : : {
8018 595 : 4386 : attrtypes[attnum]->atttypid = TypInfo[typeoid].oid;
7656 596 : 4386 : attrtypes[attnum]->attlen = TypInfo[typeoid].len;
8018 597 : 4386 : attrtypes[attnum]->attbyval = TypInfo[typeoid].byval;
598 : 4386 : attrtypes[attnum]->attalign = TypInfo[typeoid].align;
1757 599 : 4386 : attrtypes[attnum]->attstorage = TypInfo[typeoid].storage;
1753 600 : 4386 : attrtypes[attnum]->attcompression = InvalidCompressionMethod;
5514 peter_e@gmx.net 601 : 4386 : attrtypes[attnum]->attcollation = TypInfo[typeoid].collation;
602 : : /* if an array type, assume 1-dimensional attribute */
7656 tgl@sss.pgh.pa.us 603 [ + + ]: 4386 : if (TypInfo[typeoid].elem != InvalidOid &&
604 [ + + ]: 714 : attrtypes[attnum]->attlen < 0)
8104 605 : 561 : attrtypes[attnum]->attndims = 1;
606 : : else
607 : 3825 : attrtypes[attnum]->attndims = 0;
608 : : }
609 : :
610 : : /*
611 : : * If a system catalog column is collation-aware, force it to use C
612 : : * collation, so that its behavior is independent of the database's
613 : : * collation. This is essential to allow template0 to be cloned with a
614 : : * different database collation.
615 : : */
2644 616 [ + + ]: 31314 : if (OidIsValid(attrtypes[attnum]->attcollation))
617 : 5100 : attrtypes[attnum]->attcollation = C_COLLATION_OID;
618 : :
10263 bruce@momjian.us 619 : 31314 : attrtypes[attnum]->atttypmod = -1;
8575 tgl@sss.pgh.pa.us 620 : 31314 : attrtypes[attnum]->attislocal = true;
621 : :
4040 andres@anarazel.de 622 [ + + ]: 31314 : if (nullness == BOOTCOL_NULL_FORCE_NOT_NULL)
623 : : {
624 : 1734 : attrtypes[attnum]->attnotnull = true;
625 : : }
626 [ + + ]: 29580 : else if (nullness == BOOTCOL_NULL_FORCE_NULL)
627 : : {
628 : 204 : attrtypes[attnum]->attnotnull = false;
629 : : }
630 : : else
631 : : {
632 [ - + ]: 29376 : Assert(nullness == BOOTCOL_NULL_AUTO);
633 : :
634 : : /*
635 : : * Mark as "not null" if type is fixed-width and prior columns are
636 : : * likewise fixed-width and not-null. This corresponds to case where
637 : : * column can be accessed directly via C struct declaration.
638 : : */
2063 tgl@sss.pgh.pa.us 639 [ + + ]: 29376 : if (attrtypes[attnum]->attlen > 0)
640 : : {
641 : : int i;
642 : :
643 : : /* check earlier attributes */
4040 andres@anarazel.de 644 [ + + ]: 180030 : for (i = 0; i < attnum; i++)
645 : : {
2063 tgl@sss.pgh.pa.us 646 [ + + ]: 155040 : if (attrtypes[i]->attlen <= 0 ||
647 [ + - ]: 154887 : !attrtypes[i]->attnotnull)
648 : : break;
649 : : }
4040 andres@anarazel.de 650 [ + + ]: 25143 : if (i == attnum)
651 : 24990 : attrtypes[attnum]->attnotnull = true;
652 : : }
653 : : }
10841 scrappy@hub.org 654 : 31314 : }
655 : :
656 : :
657 : : /* ----------------
658 : : * InsertOneTuple
659 : : *
660 : : * If objectid is not zero, it is a specific OID to assign to the tuple.
661 : : * Otherwise, an OID will be assigned (if necessary) by heap_insert.
662 : : * ----------------
663 : : */
664 : : void
2672 andres@anarazel.de 665 : 556767 : InsertOneTuple(void)
666 : : {
667 : : HeapTuple tuple;
668 : : TupleDesc tupDesc;
669 : : int i;
670 : :
671 [ - + ]: 556767 : elog(DEBUG4, "inserting row with %d columns", numattr);
672 : :
673 : 556767 : tupDesc = CreateTupleDesc(numattr, attrtypes);
6342 tgl@sss.pgh.pa.us 674 : 556767 : tuple = heap_form_tuple(tupDesc, values, Nulls);
8639 bruce@momjian.us 675 : 556767 : pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
676 : :
8699 tgl@sss.pgh.pa.us 677 : 556767 : simple_heap_insert(boot_reldesc, tuple);
9586 JanWieck@Yahoo.com 678 : 556767 : heap_freetuple(tuple);
8328 bruce@momjian.us 679 [ - + ]: 556767 : elog(DEBUG4, "row inserted");
680 : :
681 : : /*
682 : : * Reset null markers for next tuple
683 : : */
10416 684 [ + + ]: 8820501 : for (i = 0; i < numattr; i++)
6342 tgl@sss.pgh.pa.us 685 : 8263734 : Nulls[i] = false;
10841 scrappy@hub.org 686 : 556767 : }
687 : :
688 : : /* ----------------
689 : : * InsertOneValue
690 : : * ----------------
691 : : */
692 : : void
8983 tgl@sss.pgh.pa.us 693 : 6635823 : InsertOneValue(char *value, int i)
694 : : {
695 : : Form_pg_attribute attr;
696 : : Oid typoid;
697 : : int16 typlen;
698 : : bool typbyval;
699 : : char typalign;
700 : : char typdelim;
701 : : Oid typioparam;
702 : : Oid typinput;
703 : : Oid typoutput;
704 : : Oid typcollation;
705 : :
1234 peter@eisentraut.org 706 [ + - - + ]: 6635823 : Assert(i >= 0 && i < MAXATTR);
707 : :
8272 tgl@sss.pgh.pa.us 708 [ - + ]: 6635823 : elog(DEBUG4, "inserting column %d value \"%s\"", i, value);
709 : :
25 tgl@sss.pgh.pa.us 710 :GNC 6635823 : attr = TupleDescAttr(RelationGetDescr(boot_reldesc), i);
711 : 6635823 : typoid = attr->atttypid;
712 : :
7152 tgl@sss.pgh.pa.us 713 :CBC 6635823 : boot_get_type_io_data(typoid,
714 : : &typlen, &typbyval, &typalign,
715 : : &typdelim, &typioparam,
716 : : &typinput, &typoutput,
717 : : &typcollation);
718 : :
719 : : /*
720 : : * pg_node_tree values can't be inserted normally (pg_node_tree_in would
721 : : * just error out), so provide special cases for such columns that we
722 : : * would like to fill during bootstrap.
723 : : */
25 tgl@sss.pgh.pa.us 724 [ + + ]:GNC 6635823 : if (typoid == PG_NODE_TREEOID)
725 : : {
726 : : /* pg_proc.proargdefaults */
727 [ + - + - ]: 1887 : if (RelationGetRelid(boot_reldesc) == ProcedureRelationId &&
728 : : i == Anum_pg_proc_proargdefaults - 1)
729 : 1887 : InsertOneProargdefaultsValue(value);
730 : : else /* maybe other cases later */
25 tgl@sss.pgh.pa.us 731 [ # # ]:UNC 0 : elog(ERROR, "can't handle pg_node_tree input for %s.%s",
732 : : RelationGetRelationName(boot_reldesc),
733 : : NameStr(attr->attname));
734 : : }
735 : : else
736 : : {
737 : : /* Normal case */
25 tgl@sss.pgh.pa.us 738 :GNC 6633936 : values[i] = OidInputFunctionCall(typinput, value, typioparam, -1);
739 : : }
740 : :
741 : : /*
742 : : * We use ereport not elog here so that parameters aren't evaluated unless
743 : : * the message is going to be printed, which generally it isn't
744 : : */
4515 tgl@sss.pgh.pa.us 745 [ - + ]:CBC 6635823 : ereport(DEBUG4,
746 : : (errmsg_internal("inserted -> %s",
747 : : OidOutputFunctionCall(typoutput, values[i]))));
10841 scrappy@hub.org 748 : 6635823 : }
749 : :
750 : : /* ----------------
751 : : * InsertOneProargdefaultsValue
752 : : *
753 : : * In general, proargdefaults can be a list of any expressions, but
754 : : * for bootstrap we only support a list of Const nodes. The input
755 : : * has the form of a text array, and we feed non-null elements to the
756 : : * typinput functions for the appropriate parameters.
757 : : * ----------------
758 : : */
759 : : static void
25 tgl@sss.pgh.pa.us 760 :GNC 1887 : InsertOneProargdefaultsValue(char *value)
761 : : {
762 : : int pronargs;
763 : : oidvector *proargtypes;
764 : : Datum arrayval;
765 : : Datum *array_datums;
766 : : bool *array_nulls;
767 : : int array_count;
768 : : List *proargdefaults;
769 : : char *nodestring;
770 : :
771 : : /* The pg_proc columns we need to use must have been filled already */
772 : : StaticAssertDecl(Anum_pg_proc_pronargs < Anum_pg_proc_proargdefaults,
773 : : "pronargs must come before proargdefaults");
774 : : StaticAssertDecl(Anum_pg_proc_pronargdefaults < Anum_pg_proc_proargdefaults,
775 : : "pronargdefaults must come before proargdefaults");
776 : : StaticAssertDecl(Anum_pg_proc_proargtypes < Anum_pg_proc_proargdefaults,
777 : : "proargtypes must come before proargdefaults");
778 [ - + ]: 1887 : if (Nulls[Anum_pg_proc_pronargs - 1])
25 tgl@sss.pgh.pa.us 779 [ # # ]:UNC 0 : elog(ERROR, "pronargs must not be null");
25 tgl@sss.pgh.pa.us 780 [ - + ]:GNC 1887 : if (Nulls[Anum_pg_proc_proargtypes - 1])
25 tgl@sss.pgh.pa.us 781 [ # # ]:UNC 0 : elog(ERROR, "proargtypes must not be null");
25 tgl@sss.pgh.pa.us 782 :GNC 1887 : pronargs = DatumGetInt16(values[Anum_pg_proc_pronargs - 1]);
783 : 1887 : proargtypes = DatumGetPointer(values[Anum_pg_proc_proargtypes - 1]);
784 [ - + ]: 1887 : Assert(pronargs == proargtypes->dim1);
785 : :
786 : : /* Parse the input string as an array value, then deconstruct to Datums */
787 : 1887 : arrayval = OidFunctionCall3(F_ARRAY_IN,
788 : : CStringGetDatum(value),
789 : : ObjectIdGetDatum(CSTRINGOID),
790 : : Int32GetDatum(-1));
791 : 1887 : deconstruct_array_builtin(DatumGetArrayTypeP(arrayval), CSTRINGOID,
792 : : &array_datums, &array_nulls, &array_count);
793 : :
794 : : /* The values should correspond to the last N argtypes */
795 [ - + ]: 1887 : if (array_count > pronargs)
25 tgl@sss.pgh.pa.us 796 [ # # ]:UNC 0 : elog(ERROR, "too many proargdefaults entries");
797 : :
798 : : /* Build the List of Const nodes */
25 tgl@sss.pgh.pa.us 799 :GNC 1887 : proargdefaults = NIL;
800 [ + + ]: 4896 : for (int i = 0; i < array_count; i++)
801 : : {
802 : 3009 : Oid argtype = proargtypes->values[pronargs - array_count + i];
803 : : int16 typlen;
804 : : bool typbyval;
805 : : char typalign;
806 : : char typdelim;
807 : : Oid typioparam;
808 : : Oid typinput;
809 : : Oid typoutput;
810 : : Oid typcollation;
811 : : Datum defval;
812 : : bool defnull;
813 : : Const *defConst;
814 : :
815 : 3009 : boot_get_type_io_data(argtype,
816 : : &typlen, &typbyval, &typalign,
817 : : &typdelim, &typioparam,
818 : : &typinput, &typoutput,
819 : : &typcollation);
820 : :
821 : 3009 : defnull = array_nulls[i];
822 [ + + ]: 3009 : if (defnull)
823 : 102 : defval = (Datum) 0;
824 : : else
825 : 2907 : defval = OidInputFunctionCall(typinput,
826 : 2907 : DatumGetCString(array_datums[i]),
827 : : typioparam, -1);
828 : :
829 : 3009 : defConst = makeConst(argtype,
830 : : -1, /* never any typmod */
831 : : typcollation,
832 : : typlen,
833 : : defval,
834 : : defnull,
835 : : typbyval);
836 : 3009 : proargdefaults = lappend(proargdefaults, defConst);
837 : : }
838 : :
839 : : /*
840 : : * Flatten the List to a node-tree string, then convert to a text datum,
841 : : * which is the storage representation of pg_node_tree.
842 : : */
843 : 1887 : nodestring = nodeToString(proargdefaults);
844 : 1887 : values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodestring);
845 : 1887 : Nulls[Anum_pg_proc_proargdefaults - 1] = false;
846 : :
847 : : /*
848 : : * Hack: fill in pronargdefaults with the right value. This is surely
849 : : * ugly, but it beats making the programmer do it.
850 : : */
851 : 1887 : values[Anum_pg_proc_pronargdefaults - 1] = Int16GetDatum(array_count);
852 : 1887 : Nulls[Anum_pg_proc_pronargdefaults - 1] = false;
853 : 1887 : }
854 : :
855 : : /* ----------------
856 : : * InsertOneNull
857 : : * ----------------
858 : : */
859 : : void
10841 scrappy@hub.org 860 :CBC 1627911 : InsertOneNull(int i)
861 : : {
8328 bruce@momjian.us 862 [ - + ]: 1627911 : elog(DEBUG4, "inserting column %d NULL", i);
5304 peter_e@gmx.net 863 [ + - - + ]: 1627911 : Assert(i >= 0 && i < MAXATTR);
3129 andres@anarazel.de 864 [ - + ]: 1627911 : if (TupleDescAttr(boot_reldesc->rd_att, i)->attnotnull)
3197 tgl@sss.pgh.pa.us 865 [ # # ]:UBC 0 : elog(ERROR,
866 : : "NULL value specified for not-null column \"%s\" of relation \"%s\"",
867 : : NameStr(TupleDescAttr(boot_reldesc->rd_att, i)->attname),
868 : : RelationGetRelationName(boot_reldesc));
9420 tgl@sss.pgh.pa.us 869 :CBC 1627911 : values[i] = PointerGetDatum(NULL);
6342 870 : 1627911 : Nulls[i] = true;
10841 scrappy@hub.org 871 : 1627911 : }
872 : :
873 : : /* ----------------
874 : : * cleanup
875 : : * ----------------
876 : : */
877 : : static void
8327 tgl@sss.pgh.pa.us 878 : 51 : cleanup(void)
879 : : {
8626 880 [ - + ]: 51 : if (boot_reldesc != NULL)
8626 tgl@sss.pgh.pa.us 881 :UBC 0 : closerel(NULL);
10841 scrappy@hub.org 882 :CBC 51 : }
883 : :
884 : : /* ----------------
885 : : * populate_typ_list
886 : : *
887 : : * Load the Typ list by reading pg_type.
888 : : * ----------------
889 : : */
890 : : static void
1817 tomas.vondra@postgre 891 : 102 : populate_typ_list(void)
892 : : {
893 : : Relation rel;
894 : : TableScanDesc scan;
895 : : HeapTuple tup;
896 : : MemoryContext old;
897 : :
898 [ - + ]: 102 : Assert(Typ == NIL);
899 : :
2017 tgl@sss.pgh.pa.us 900 : 102 : rel = table_open(TypeRelationId, NoLock);
901 : 102 : scan = table_beginscan_catalog(rel, 0, NULL);
1817 tomas.vondra@postgre 902 : 102 : old = MemoryContextSwitchTo(TopMemoryContext);
2017 tgl@sss.pgh.pa.us 903 [ + + ]: 21828 : while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL)
904 : : {
905 : 21726 : Form_pg_type typForm = (Form_pg_type) GETSTRUCT(tup);
906 : : struct typmap *newtyp;
907 : :
95 michael@paquier.xyz 908 :GNC 21726 : newtyp = palloc_object(struct typmap);
1817 tomas.vondra@postgre 909 :CBC 21726 : Typ = lappend(Typ, newtyp);
910 : :
911 : 21726 : newtyp->am_oid = typForm->oid;
912 : 21726 : memcpy(&newtyp->am_typ, typForm, sizeof(newtyp->am_typ));
913 : : }
914 : 102 : MemoryContextSwitchTo(old);
2017 tgl@sss.pgh.pa.us 915 : 102 : table_endscan(scan);
916 : 102 : table_close(rel, NoLock);
917 : 102 : }
918 : :
919 : : /* ----------------
920 : : * gettype
921 : : *
922 : : * NB: this is really ugly; it will return an integer index into TypInfo[],
923 : : * and not an OID at all, until the first reference to a type not known in
924 : : * TypInfo[]. At that point it will read and cache pg_type in Typ,
925 : : * and subsequently return a real OID (and set the global pointer Ap to
926 : : * point at the found row in Typ). So caller must check whether Typ is
927 : : * still NIL to determine what the return value is!
928 : : * ----------------
929 : : */
930 : : static Oid
10841 scrappy@hub.org 931 : 31365 : gettype(char *type)
932 : : {
1817 tomas.vondra@postgre 933 [ + + ]: 31365 : if (Typ != NIL)
934 : : {
935 : : ListCell *lc;
936 : :
1768 tgl@sss.pgh.pa.us 937 [ + - + + : 501075 : foreach(lc, Typ)
+ + ]
938 : : {
1817 tomas.vondra@postgre 939 : 501024 : struct typmap *app = lfirst(lc);
940 : :
941 [ + + ]: 501024 : if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
942 : : {
943 : 26877 : Ap = app;
944 : 26877 : return app->am_oid;
945 : : }
946 : : }
947 : :
948 : : /*
949 : : * The type wasn't known; reload the pg_type contents and check again
950 : : * to handle composite types, added since last populating the list.
951 : : */
952 : :
953 : 51 : list_free_deep(Typ);
954 : 51 : Typ = NIL;
955 : 51 : populate_typ_list();
956 : :
957 : : /*
958 : : * Calling gettype would result in infinite recursion for types
959 : : * missing in pg_type, so just repeat the lookup.
960 : : */
1768 tgl@sss.pgh.pa.us 961 [ + - + - : 11577 : foreach(lc, Typ)
+ - ]
962 : : {
1817 tomas.vondra@postgre 963 : 11577 : struct typmap *app = lfirst(lc);
964 : :
965 [ + + ]: 11577 : if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0)
966 : : {
967 : 51 : Ap = app;
968 : 51 : return app->am_oid;
969 : : }
970 : : }
971 : : }
972 : : else
973 : : {
974 : : int i;
975 : :
8725 tgl@sss.pgh.pa.us 976 [ + + ]: 42483 : for (i = 0; i < n_types; i++)
977 : : {
8018 978 [ + + ]: 42432 : if (strncmp(type, TypInfo[i].name, NAMEDATALEN) == 0)
10057 bruce@momjian.us 979 : 4386 : return i;
980 : : }
981 : : /* Not in TypInfo, so we'd better be able to read pg_type now */
8328 982 [ - + ]: 51 : elog(DEBUG4, "external type: %s", type);
1817 tomas.vondra@postgre 983 : 51 : populate_typ_list();
10057 bruce@momjian.us 984 : 51 : return gettype(type);
985 : : }
8272 tgl@sss.pgh.pa.us 986 [ # # ]:UBC 0 : elog(ERROR, "unrecognized type \"%s\"", type);
987 : : /* not reached, here to make compiler happy */
988 : : return 0;
989 : : }
990 : :
991 : : /* ----------------
992 : : * boot_get_type_io_data
993 : : *
994 : : * Obtain type I/O information at bootstrap time. This intentionally has
995 : : * an API very close to that of lsyscache.c's get_type_io_data, except that
996 : : * we only support obtaining the typinput and typoutput routines, not
997 : : * the binary I/O routines, and we also return the type's collation.
998 : : * This is exported so that array_in and array_out can be made to work
999 : : * during early bootstrap.
1000 : : * ----------------
1001 : : */
1002 : : void
7152 tgl@sss.pgh.pa.us 1003 :CBC 6670656 : boot_get_type_io_data(Oid typid,
1004 : : int16 *typlen,
1005 : : bool *typbyval,
1006 : : char *typalign,
1007 : : char *typdelim,
1008 : : Oid *typioparam,
1009 : : Oid *typinput,
1010 : : Oid *typoutput,
1011 : : Oid *typcollation)
1012 : : {
1817 tomas.vondra@postgre 1013 [ + + ]: 6670656 : if (Typ != NIL)
1014 : : {
1015 : : /* We have the boot-time contents of pg_type, so use it */
1016 : 2627529 : struct typmap *ap = NULL;
1017 : : ListCell *lc;
1018 : :
1768 tgl@sss.pgh.pa.us 1019 [ + - + - : 23294901 : foreach(lc, Typ)
+ - ]
1020 : : {
1817 tomas.vondra@postgre 1021 : 23294901 : ap = lfirst(lc);
1022 [ + + ]: 23294901 : if (ap->am_oid == typid)
1023 : 2627529 : break;
1024 : : }
1025 : :
1026 [ + - - + ]: 2627529 : if (!ap || ap->am_oid != typid)
7152 tgl@sss.pgh.pa.us 1027 [ # # ]:UBC 0 : elog(ERROR, "type OID %u not found in Typ list", typid);
1028 : :
7152 tgl@sss.pgh.pa.us 1029 :CBC 2627529 : *typlen = ap->am_typ.typlen;
1030 : 2627529 : *typbyval = ap->am_typ.typbyval;
1031 : 2627529 : *typalign = ap->am_typ.typalign;
1032 : 2627529 : *typdelim = ap->am_typ.typdelim;
1033 : :
1034 : : /* XXX this logic must match getTypeIOParam() */
1035 [ + + ]: 2627529 : if (OidIsValid(ap->am_typ.typelem))
1036 : 74256 : *typioparam = ap->am_typ.typelem;
1037 : : else
1038 : 2553273 : *typioparam = typid;
1039 : :
1040 : 2627529 : *typinput = ap->am_typ.typinput;
1041 : 2627529 : *typoutput = ap->am_typ.typoutput;
1042 : :
25 tgl@sss.pgh.pa.us 1043 :GNC 2627529 : *typcollation = ap->am_typ.typcollation;
1044 : : }
1045 : : else
1046 : : {
1047 : : /* We don't have pg_type yet, so use the hard-wired TypInfo array */
1048 : : int typeindex;
1049 : :
7152 tgl@sss.pgh.pa.us 1050 [ + - ]:CBC 34024038 : for (typeindex = 0; typeindex < n_types; typeindex++)
1051 : : {
1052 [ + + ]: 34024038 : if (TypInfo[typeindex].oid == typid)
1053 : 4043127 : break;
1054 : : }
1055 [ - + ]: 4043127 : if (typeindex >= n_types)
7152 tgl@sss.pgh.pa.us 1056 [ # # ]:UBC 0 : elog(ERROR, "type OID %u not found in TypInfo", typid);
1057 : :
7152 tgl@sss.pgh.pa.us 1058 :CBC 4043127 : *typlen = TypInfo[typeindex].len;
1059 : 4043127 : *typbyval = TypInfo[typeindex].byval;
1060 : 4043127 : *typalign = TypInfo[typeindex].align;
1061 : : /* We assume typdelim is ',' for all boot-time types */
1062 : 4043127 : *typdelim = ',';
1063 : :
1064 : : /* XXX this logic must match getTypeIOParam() */
1065 [ + + ]: 4043127 : if (OidIsValid(TypInfo[typeindex].elem))
1066 : 390558 : *typioparam = TypInfo[typeindex].elem;
1067 : : else
1068 : 3652569 : *typioparam = typid;
1069 : :
1070 : 4043127 : *typinput = TypInfo[typeindex].inproc;
1071 : 4043127 : *typoutput = TypInfo[typeindex].outproc;
1072 : :
25 tgl@sss.pgh.pa.us 1073 :GNC 4043127 : *typcollation = TypInfo[typeindex].collation;
1074 : : }
7152 1075 : 6670656 : }
1076 : :
1077 : : /* ----------------
1078 : : * boot_get_role_oid
1079 : : *
1080 : : * Look up a role name at bootstrap time. This is equivalent to
1081 : : * get_role_oid(rolname, true): return the role OID or InvalidOid if
1082 : : * not found. We only need to cope with built-in role names.
1083 : : * ----------------
1084 : : */
1085 : : Oid
10 1086 : 4233 : boot_get_role_oid(const char *rolname)
1087 : : {
1088 [ + - ]: 8007 : for (int i = 0; i < lengthof(RolInfo); i++)
1089 : : {
1090 [ + + ]: 8007 : if (strcmp(RolInfo[i].rolname, rolname) == 0)
1091 : 4233 : return RolInfo[i].oid;
1092 : : }
10 tgl@sss.pgh.pa.us 1093 :UNC 0 : return InvalidOid;
10 tgl@sss.pgh.pa.us 1094 :ECB (6447459) : }
1095 : :
1096 : : /* ----------------
1097 : : * AllocateAttribute
1098 : : *
1099 : : * Note: bootstrap never sets any per-column ACLs, so we only need
1100 : : * ATTRIBUTE_FIXED_PART_SIZE space per attribute.
1101 : : * ----------------
1102 : : */
1103 : : static Form_pg_attribute
8626 tgl@sss.pgh.pa.us 1104 :CBC 1734 : AllocateAttribute(void)
1105 : : {
3484 1106 : 1734 : return (Form_pg_attribute)
1107 : 1734 : MemoryContextAllocZero(TopMemoryContext, ATTRIBUTE_FIXED_PART_SIZE);
1108 : : }
1109 : :
1110 : : /*
1111 : : * index_register() -- record an index that has been set up for building
1112 : : * later.
1113 : : *
1114 : : * At bootstrap time, we define a bunch of indexes on system catalogs.
1115 : : * We postpone actually building the indexes until just before we're
1116 : : * finished with initialization, however. This is because the indexes
1117 : : * themselves have catalog entries, and those have to be included in the
1118 : : * indexes on those catalogs. Doing it in two phases is the simplest
1119 : : * way of making sure the indexes have the right contents at the end.
1120 : : */
1121 : : void
8755 1122 : 8109 : index_register(Oid heap,
1123 : : Oid ind,
1124 : : const IndexInfo *indexInfo)
1125 : : {
1126 : : IndexList *newind;
1127 : : MemoryContext oldcxt;
1128 : :
1129 : : /*
1130 : : * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
1131 : : * bootstrap time. we'll declare the indexes now, but want to create them
1132 : : * later.
1133 : : */
1134 : :
9391 1135 [ + + ]: 8109 : if (nogc == NULL)
8103 neilc@samurai.com 1136 : 51 : nogc = AllocSetContextCreate(NULL,
1137 : : "BootstrapNoGC",
1138 : : ALLOCSET_DEFAULT_SIZES);
1139 : :
9391 tgl@sss.pgh.pa.us 1140 : 8109 : oldcxt = MemoryContextSwitchTo(nogc);
1141 : :
95 michael@paquier.xyz 1142 :GNC 8109 : newind = palloc_object(IndexList);
8755 tgl@sss.pgh.pa.us 1143 :CBC 8109 : newind->il_heap = heap;
1144 : 8109 : newind->il_ind = ind;
95 michael@paquier.xyz 1145 :GNC 8109 : newind->il_info = palloc_object(IndexInfo);
1146 : :
9375 tgl@sss.pgh.pa.us 1147 :CBC 8109 : memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
1148 : : /* expressions will likely be null, but may as well copy it */
3293 peter_e@gmx.net 1149 : 16218 : newind->il_info->ii_Expressions =
8327 tgl@sss.pgh.pa.us 1150 : 8109 : copyObject(indexInfo->ii_Expressions);
1151 : 8109 : newind->il_info->ii_ExpressionsState = NIL;
1152 : : /* predicate will likely be null, but may as well copy it */
3293 peter_e@gmx.net 1153 : 16218 : newind->il_info->ii_Predicate =
9008 tgl@sss.pgh.pa.us 1154 : 8109 : copyObject(indexInfo->ii_Predicate);
3288 andres@anarazel.de 1155 : 8109 : newind->il_info->ii_PredicateState = NULL;
1156 : : /* no exclusion constraints at bootstrap time, so no need to copy */
5942 tgl@sss.pgh.pa.us 1157 [ - + ]: 8109 : Assert(indexInfo->ii_ExclusionOps == NULL);
1158 [ - + ]: 8109 : Assert(indexInfo->ii_ExclusionProcs == NULL);
1159 [ - + ]: 8109 : Assert(indexInfo->ii_ExclusionStrats == NULL);
1160 : :
10416 bruce@momjian.us 1161 : 8109 : newind->il_next = ILHead;
1162 : 8109 : ILHead = newind;
1163 : :
1164 : 8109 : MemoryContextSwitchTo(oldcxt);
10841 scrappy@hub.org 1165 : 8109 : }
1166 : :
1167 : :
1168 : : /*
1169 : : * build_indices -- fill in all the indexes registered earlier
1170 : : */
1171 : : void
8103 neilc@samurai.com 1172 : 51 : build_indices(void)
1173 : : {
1174 [ + + ]: 8160 : for (; ILHead != NULL; ILHead = ILHead->il_next)
1175 : : {
1176 : : Relation heap;
1177 : : Relation ind;
1178 : :
1179 : : /* need not bother with locks during bootstrap */
2610 andres@anarazel.de 1180 : 8109 : heap = table_open(ILHead->il_heap, NoLock);
7167 tgl@sss.pgh.pa.us 1181 : 8109 : ind = index_open(ILHead->il_ind, NoLock);
1182 : :
2607 michael@paquier.xyz 1183 : 8109 : index_build(heap, ind, ILHead->il_info, false, false);
1184 : :
7167 tgl@sss.pgh.pa.us 1185 : 8109 : index_close(ind, NoLock);
2610 andres@anarazel.de 1186 : 8109 : table_close(heap, NoLock);
1187 : : }
10841 scrappy@hub.org 1188 : 51 : }
|