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