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