Line data Source code
1 : %{
2 : /*-------------------------------------------------------------------------
3 : *
4 : * bootparse.y
5 : * yacc grammar for the "bootstrap" mode (BKI file format)
6 : *
7 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : *
11 : * IDENTIFICATION
12 : * src/backend/bootstrap/bootparse.y
13 : *
14 : *-------------------------------------------------------------------------
15 : */
16 :
17 : #include "postgres.h"
18 :
19 : #include <unistd.h>
20 :
21 : #include "bootstrap/bootstrap.h"
22 : #include "catalog/heap.h"
23 : #include "catalog/namespace.h"
24 : #include "catalog/pg_am.h"
25 : #include "catalog/pg_authid.h"
26 : #include "catalog/pg_class.h"
27 : #include "catalog/pg_namespace.h"
28 : #include "catalog/pg_tablespace.h"
29 : #include "catalog/toasting.h"
30 : #include "commands/defrem.h"
31 : #include "miscadmin.h"
32 : #include "nodes/makefuncs.h"
33 : #include "utils/memutils.h"
34 :
35 : #include "bootparse.h"
36 :
37 :
38 : /*
39 : * Bison doesn't allocate anything that needs to live across parser calls,
40 : * so we can easily have it use palloc instead of malloc. This prevents
41 : * memory leaks if we error out during parsing.
42 : */
43 : #define YYMALLOC palloc
44 : #define YYFREE pfree
45 :
46 : static MemoryContext per_line_ctx = NULL;
47 :
48 : static void
49 1154640 : do_start(void)
50 : {
51 : Assert(CurrentMemoryContext == CurTransactionContext);
52 : /* First time through, create the per-line working context */
53 1154640 : if (per_line_ctx == NULL)
54 102 : per_line_ctx = AllocSetContextCreate(CurTransactionContext,
55 : "bootstrap per-line processing",
56 : ALLOCSET_DEFAULT_SIZES);
57 1154640 : MemoryContextSwitchTo(per_line_ctx);
58 1154640 : }
59 :
60 :
61 : static void
62 1154640 : do_end(void)
63 : {
64 : /* Reclaim memory allocated while processing this line */
65 1154640 : MemoryContextSwitchTo(CurTransactionContext);
66 1154640 : MemoryContextReset(per_line_ctx);
67 1154640 : CHECK_FOR_INTERRUPTS(); /* allow SIGINT to kill bootstrap run */
68 1154640 : if (isatty(0))
69 : {
70 0 : printf("bootstrap> ");
71 0 : fflush(stdout);
72 : }
73 1154640 : }
74 :
75 :
76 : static int num_columns_read = 0;
77 :
78 : %}
79 :
80 : %parse-param {yyscan_t yyscanner}
81 : %lex-param {yyscan_t yyscanner}
82 : %pure-parser
83 : %expect 0
84 : %name-prefix="boot_yy"
85 :
86 : %union
87 : {
88 : List *list;
89 : IndexElem *ielem;
90 : char *str;
91 : const char *kw;
92 : int ival;
93 : Oid oidval;
94 : }
95 :
96 : %type <list> boot_index_params
97 : %type <ielem> boot_index_param
98 : %type <str> boot_ident
99 : %type <ival> optbootstrap optsharedrelation boot_column_nullness
100 : %type <oidval> oidspec optrowtypeoid
101 :
102 : %token <str> ID
103 : %token COMMA EQUALS LPAREN RPAREN
104 : /* NULLVAL is a reserved keyword */
105 : %token NULLVAL
106 : /* All the rest are unreserved, and should be handled in boot_ident! */
107 : %token <kw> OPEN XCLOSE XCREATE INSERT_TUPLE
108 : %token <kw> XDECLARE INDEX ON USING XBUILD INDICES UNIQUE XTOAST
109 : %token <kw> OBJ_ID XBOOTSTRAP XSHARED_RELATION XROWTYPE_OID
110 : %token <kw> XFORCE XNOT XNULL
111 :
112 : %start TopLevel
113 :
114 : %%
115 :
116 : TopLevel:
117 : Boot_Queries
118 : |
119 : ;
120 :
121 : Boot_Queries:
122 : Boot_Query
123 : | Boot_Queries Boot_Query
124 : ;
125 :
126 : Boot_Query :
127 : Boot_OpenStmt
128 : | Boot_CloseStmt
129 : | Boot_CreateStmt
130 : | Boot_InsertStmt
131 : | Boot_DeclareIndexStmt
132 : | Boot_DeclareUniqueIndexStmt
133 : | Boot_DeclareToastStmt
134 : | Boot_BuildIndsStmt
135 : ;
136 :
137 : Boot_OpenStmt:
138 : OPEN boot_ident
139 : {
140 6120 : do_start();
141 6120 : boot_openrel($2);
142 6120 : do_end();
143 :
144 : (void) yynerrs; /* suppress compiler warning */
145 : }
146 : ;
147 :
148 : Boot_CloseStmt:
149 : XCLOSE boot_ident
150 : {
151 6528 : do_start();
152 6528 : closerel($2);
153 6528 : do_end();
154 : }
155 : ;
156 :
157 : Boot_CreateStmt:
158 : XCREATE boot_ident oidspec optbootstrap optsharedrelation optrowtypeoid LPAREN
159 : {
160 6528 : do_start();
161 6528 : numattr = 0;
162 6528 : elog(DEBUG4, "creating%s%s relation %s %u",
163 : $4 ? " bootstrap" : "",
164 : $5 ? " shared" : "",
165 : $2,
166 : $3);
167 : }
168 : boot_column_list
169 : {
170 6528 : do_end();
171 : }
172 : RPAREN
173 : {
174 : TupleDesc tupdesc;
175 : bool shared_relation;
176 : bool mapped_relation;
177 :
178 6528 : do_start();
179 :
180 6528 : tupdesc = CreateTupleDesc(numattr, attrtypes);
181 :
182 6528 : shared_relation = $5;
183 :
184 : /*
185 : * The catalogs that use the relation mapper are the
186 : * bootstrap catalogs plus the shared catalogs. If this
187 : * ever gets more complicated, we should invent a BKI
188 : * keyword to mark the mapped catalogs, but for now a
189 : * quick hack seems the most appropriate thing. Note in
190 : * particular that all "nailed" heap rels (see formrdesc
191 : * in relcache.c) must be mapped.
192 : */
193 6528 : mapped_relation = ($4 || shared_relation);
194 :
195 6528 : if ($4)
196 : {
197 : TransactionId relfrozenxid;
198 : MultiXactId relminmxid;
199 :
200 408 : if (boot_reldesc)
201 : {
202 0 : elog(DEBUG4, "create bootstrap: warning, open relation exists, closing first");
203 0 : closerel(NULL);
204 : }
205 :
206 408 : boot_reldesc = heap_create($2,
207 : PG_CATALOG_NAMESPACE,
208 : shared_relation ? GLOBALTABLESPACE_OID : 0,
209 408 : $3,
210 : InvalidOid,
211 : HEAP_TABLE_AM_OID,
212 : tupdesc,
213 : RELKIND_RELATION,
214 : RELPERSISTENCE_PERMANENT,
215 : shared_relation,
216 : mapped_relation,
217 : true,
218 : &relfrozenxid,
219 : &relminmxid,
220 : true);
221 408 : elog(DEBUG4, "bootstrap relation created");
222 : }
223 : else
224 : {
225 : Oid id;
226 :
227 6120 : id = heap_create_with_catalog($2,
228 : PG_CATALOG_NAMESPACE,
229 : shared_relation ? GLOBALTABLESPACE_OID : 0,
230 6120 : $3,
231 6120 : $6,
232 : InvalidOid,
233 : BOOTSTRAP_SUPERUSERID,
234 : HEAP_TABLE_AM_OID,
235 : tupdesc,
236 : NIL,
237 : RELKIND_RELATION,
238 : RELPERSISTENCE_PERMANENT,
239 : shared_relation,
240 : mapped_relation,
241 : ONCOMMIT_NOOP,
242 : (Datum) 0,
243 : false,
244 : true,
245 : false,
246 : InvalidOid,
247 : NULL);
248 6120 : elog(DEBUG4, "relation created with OID %u", id);
249 : }
250 6528 : do_end();
251 : }
252 : ;
253 :
254 : Boot_InsertStmt:
255 : INSERT_TUPLE
256 : {
257 1112616 : do_start();
258 1112616 : elog(DEBUG4, "inserting row");
259 1112616 : num_columns_read = 0;
260 : }
261 : LPAREN boot_column_val_list RPAREN
262 : {
263 1112616 : if (num_columns_read != numattr)
264 0 : elog(ERROR, "incorrect number of columns in row (expected %d, got %d)",
265 : numattr, num_columns_read);
266 1112616 : if (boot_reldesc == NULL)
267 0 : elog(FATAL, "relation not open");
268 1112616 : InsertOneTuple();
269 1112616 : do_end();
270 : }
271 : ;
272 :
273 : Boot_DeclareIndexStmt:
274 : XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
275 : {
276 1428 : IndexStmt *stmt = makeNode(IndexStmt);
277 : Oid relationId;
278 :
279 1428 : elog(DEBUG4, "creating index \"%s\"", $3);
280 :
281 1428 : do_start();
282 :
283 1428 : stmt->idxname = $3;
284 1428 : stmt->relation = makeRangeVar(NULL, $6, -1);
285 1428 : stmt->accessMethod = $8;
286 1428 : stmt->tableSpace = NULL;
287 1428 : stmt->indexParams = $10;
288 1428 : stmt->indexIncludingParams = NIL;
289 1428 : stmt->options = NIL;
290 1428 : stmt->whereClause = NULL;
291 1428 : stmt->excludeOpNames = NIL;
292 1428 : stmt->idxcomment = NULL;
293 1428 : stmt->indexOid = InvalidOid;
294 1428 : stmt->oldNumber = InvalidRelFileNumber;
295 1428 : stmt->oldCreateSubid = InvalidSubTransactionId;
296 1428 : stmt->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
297 1428 : stmt->unique = false;
298 1428 : stmt->primary = false;
299 1428 : stmt->isconstraint = false;
300 1428 : stmt->deferrable = false;
301 1428 : stmt->initdeferred = false;
302 1428 : stmt->transformed = false;
303 1428 : stmt->concurrent = false;
304 1428 : stmt->if_not_exists = false;
305 1428 : stmt->reset_default_tblspc = false;
306 :
307 : /* locks and races need not concern us in bootstrap mode */
308 1428 : relationId = RangeVarGetRelid(stmt->relation, NoLock,
309 : false);
310 :
311 1428 : DefineIndex(NULL,
312 : relationId,
313 : stmt,
314 1428 : $4,
315 : InvalidOid,
316 : InvalidOid,
317 : -1,
318 : false,
319 : false,
320 : false,
321 : true, /* skip_build */
322 : false);
323 1428 : do_end();
324 : }
325 : ;
326 :
327 : Boot_DeclareUniqueIndexStmt:
328 : XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
329 : {
330 11220 : IndexStmt *stmt = makeNode(IndexStmt);
331 : Oid relationId;
332 :
333 11220 : elog(DEBUG4, "creating unique index \"%s\"", $4);
334 :
335 11220 : do_start();
336 :
337 11220 : stmt->idxname = $4;
338 11220 : stmt->relation = makeRangeVar(NULL, $7, -1);
339 11220 : stmt->accessMethod = $9;
340 11220 : stmt->tableSpace = NULL;
341 11220 : stmt->indexParams = $11;
342 11220 : stmt->indexIncludingParams = NIL;
343 11220 : stmt->options = NIL;
344 11220 : stmt->whereClause = NULL;
345 11220 : stmt->excludeOpNames = NIL;
346 11220 : stmt->idxcomment = NULL;
347 11220 : stmt->indexOid = InvalidOid;
348 11220 : stmt->oldNumber = InvalidRelFileNumber;
349 11220 : stmt->oldCreateSubid = InvalidSubTransactionId;
350 11220 : stmt->oldFirstRelfilelocatorSubid = InvalidSubTransactionId;
351 11220 : stmt->unique = true;
352 11220 : stmt->primary = false;
353 11220 : stmt->isconstraint = false;
354 11220 : stmt->deferrable = false;
355 11220 : stmt->initdeferred = false;
356 11220 : stmt->transformed = false;
357 11220 : stmt->concurrent = false;
358 11220 : stmt->if_not_exists = false;
359 11220 : stmt->reset_default_tblspc = false;
360 :
361 : /* locks and races need not concern us in bootstrap mode */
362 11220 : relationId = RangeVarGetRelid(stmt->relation, NoLock,
363 : false);
364 :
365 11220 : DefineIndex(NULL,
366 : relationId,
367 : stmt,
368 11220 : $5,
369 : InvalidOid,
370 : InvalidOid,
371 : -1,
372 : false,
373 : false,
374 : false,
375 : true, /* skip_build */
376 : false);
377 11220 : do_end();
378 : }
379 : ;
380 :
381 : Boot_DeclareToastStmt:
382 : XDECLARE XTOAST oidspec oidspec ON boot_ident
383 : {
384 3570 : elog(DEBUG4, "creating toast table for table \"%s\"", $6);
385 :
386 3570 : do_start();
387 :
388 3570 : BootstrapToastTable($6, $3, $4);
389 3570 : do_end();
390 : }
391 : ;
392 :
393 : Boot_BuildIndsStmt:
394 : XBUILD INDICES
395 : {
396 102 : do_start();
397 102 : build_indices();
398 102 : do_end();
399 : }
400 : ;
401 :
402 :
403 : boot_index_params:
404 8262 : boot_index_params COMMA boot_index_param { $$ = lappend($1, $3); }
405 12648 : | boot_index_param { $$ = list_make1($1); }
406 : ;
407 :
408 : boot_index_param:
409 : boot_ident boot_ident
410 : {
411 20910 : IndexElem *n = makeNode(IndexElem);
412 :
413 20910 : n->name = $1;
414 20910 : n->expr = NULL;
415 20910 : n->indexcolname = NULL;
416 20910 : n->collation = NIL;
417 20910 : n->opclass = list_make1(makeString($2));
418 20910 : n->ordering = SORTBY_DEFAULT;
419 20910 : n->nulls_ordering = SORTBY_NULLS_DEFAULT;
420 20910 : n->location = -1;
421 20910 : $$ = n;
422 : }
423 : ;
424 :
425 : optbootstrap:
426 408 : XBOOTSTRAP { $$ = 1; }
427 6120 : | { $$ = 0; }
428 : ;
429 :
430 : optsharedrelation:
431 1122 : XSHARED_RELATION { $$ = 1; }
432 5406 : | { $$ = 0; }
433 : ;
434 :
435 : optrowtypeoid:
436 918 : XROWTYPE_OID oidspec { $$ = $2; }
437 5610 : | { $$ = InvalidOid; }
438 : ;
439 :
440 : boot_column_list:
441 : boot_column_def
442 : | boot_column_list COMMA boot_column_def
443 : ;
444 :
445 : boot_column_def:
446 : boot_ident EQUALS boot_ident boot_column_nullness
447 : {
448 61710 : if (++numattr > MAXATTR)
449 0 : elog(FATAL, "too many columns");
450 61710 : DefineAttr($1, $3, numattr-1, $4);
451 : }
452 : ;
453 :
454 : boot_column_nullness:
455 3468 : XFORCE XNOT XNULL { $$ = BOOTCOL_NULL_FORCE_NOT_NULL; }
456 408 : | XFORCE XNULL { $$ = BOOTCOL_NULL_FORCE_NULL; }
457 57834 : | { $$ = BOOTCOL_NULL_AUTO; }
458 : ;
459 :
460 : oidspec:
461 27234 : boot_ident { $$ = atooid($1); }
462 : ;
463 :
464 : boot_column_val_list:
465 : boot_column_val
466 : | boot_column_val_list boot_column_val
467 : | boot_column_val_list COMMA boot_column_val
468 : ;
469 :
470 : boot_column_val:
471 : boot_ident
472 13245228 : { InsertOneValue($1, num_columns_read++); }
473 : | NULLVAL
474 3266634 : { InsertOneNull(num_columns_read++); }
475 : ;
476 :
477 : boot_ident:
478 13498392 : ID { $$ = $1; }
479 0 : | OPEN { $$ = pstrdup($1); }
480 0 : | XCLOSE { $$ = pstrdup($1); }
481 0 : | XCREATE { $$ = pstrdup($1); }
482 0 : | INSERT_TUPLE { $$ = pstrdup($1); }
483 0 : | XDECLARE { $$ = pstrdup($1); }
484 0 : | INDEX { $$ = pstrdup($1); }
485 0 : | ON { $$ = pstrdup($1); }
486 0 : | USING { $$ = pstrdup($1); }
487 0 : | XBUILD { $$ = pstrdup($1); }
488 0 : | INDICES { $$ = pstrdup($1); }
489 0 : | UNIQUE { $$ = pstrdup($1); }
490 0 : | XTOAST { $$ = pstrdup($1); }
491 0 : | OBJ_ID { $$ = pstrdup($1); }
492 0 : | XBOOTSTRAP { $$ = pstrdup($1); }
493 0 : | XSHARED_RELATION { $$ = pstrdup($1); }
494 0 : | XROWTYPE_OID { $$ = pstrdup($1); }
495 0 : | XFORCE { $$ = pstrdup($1); }
496 0 : | XNOT { $$ = pstrdup($1); }
497 0 : | XNULL { $$ = pstrdup($1); }
498 : ;
499 : %%
|