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