1 %{
2 /*-------------------------------------------------------------------------
3 *
4 * bootparse.y
5 * yacc grammar for the "bootstrap" mode (BKI file format)
6 *
7 * Portions Copyright (c) 1996-2017, 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 int ival;
109 Oid oidval;
110 }
111
112 %type <list> boot_index_params
113 %type <ielem> boot_index_param
114 %type <str> boot_ident
115 %type <ival> optbootstrap optsharedrelation optwithoutoids boot_column_nullness
116 %type <oidval> oidspec optoideq optrowtypeoid
117
118 %token <str> ID
119 %token OPEN XCLOSE XCREATE INSERT_TUPLE
120 %token XDECLARE INDEX ON USING XBUILD INDICES UNIQUE XTOAST
121 %token COMMA EQUALS LPAREN RPAREN
122 %token OBJ_ID XBOOTSTRAP XSHARED_RELATION XWITHOUT_OIDS XROWTYPE_OID NULLVAL
123 %token XFORCE XNOT XNULL
124
125 %start TopLevel
126
127 %nonassoc low
128 %nonassoc high
129
130 %%
131
132 TopLevel:
133 Boot_Queries
134 |
135 ;
136
137 Boot_Queries:
138 Boot_Query
139 | Boot_Queries Boot_Query
140 ;
141
142 Boot_Query :
143 Boot_OpenStmt
144 | Boot_CloseStmt
145 | Boot_CreateStmt
146 | Boot_InsertStmt
147 | Boot_DeclareIndexStmt
148 | Boot_DeclareUniqueIndexStmt
149 | Boot_DeclareToastStmt
150 | Boot_BuildIndsStmt
151 ;
152
153 Boot_OpenStmt:
154 OPEN boot_ident
155 {
156 do_start();
157 boot_openrel($2);
158 do_end();
159 }
160 ;
161
162 Boot_CloseStmt:
163 XCLOSE boot_ident %prec low
164 {
165 do_start();
166 closerel($2);
167 do_end();
168 }
169 | XCLOSE %prec high
170 {
171 do_start();
172 closerel(NULL);
173 do_end();
174 }
175 ;
176
177 Boot_CreateStmt:
178 XCREATE boot_ident oidspec optbootstrap optsharedrelation optwithoutoids optrowtypeoid LPAREN
179 {
180 do_start();
181 numattr = 0;
182 elog(DEBUG4, "creating%s%s relation %s %u",
183 $4 ? " bootstrap" : "",
184 $5 ? " shared" : "",
185 $2,
186 $3);
187 }
188 boot_column_list
189 {
190 do_end();
191 }
192 RPAREN
193 {
194 TupleDesc tupdesc;
195 bool shared_relation;
196 bool mapped_relation;
197
198 do_start();
199
200 tupdesc = CreateTupleDesc(numattr, !($6), attrtypes);
201
202 shared_relation = $5;
203
204 /*
205 * The catalogs that use the relation mapper are the
206 * bootstrap catalogs plus the shared catalogs. If this
207 * ever gets more complicated, we should invent a BKI
208 * keyword to mark the mapped catalogs, but for now a
209 * quick hack seems the most appropriate thing. Note in
210 * particular that all "nailed" heap rels (see formrdesc
211 * in relcache.c) must be mapped.
212 */
213 mapped_relation = ($4 || shared_relation);
214
215 if ($4)
216 {
217 if (boot_reldesc)
218 {
219 elog(DEBUG4, "create bootstrap: warning, open relation exists, closing first");
220 closerel(NULL);
221 }
222
223 boot_reldesc = heap_create($2,
224 PG_CATALOG_NAMESPACE,
225 shared_relation ? GLOBALTABLESPACE_OID : 0,
226 $3,
227 InvalidOid,
228 tupdesc,
229 RELKIND_RELATION,
230 RELPERSISTENCE_PERMANENT,
231 shared_relation,
232 mapped_relation,
233 true);
234 elog(DEBUG4, "bootstrap relation created");
235 }
236 else
237 {
238 Oid id;
239
240 id = heap_create_with_catalog($2,
241 PG_CATALOG_NAMESPACE,
242 shared_relation ? GLOBALTABLESPACE_OID : 0,
243 $3,
244 $7,
245 InvalidOid,
246 BOOTSTRAP_SUPERUSERID,
247 tupdesc,
248 NIL,
249 RELKIND_RELATION,
250 RELPERSISTENCE_PERMANENT,
251 shared_relation,
252 mapped_relation,
253 true,
254 0,
255 ONCOMMIT_NOOP,
256 (Datum) 0,
257 false,
258 true,
259 false,
260 NULL);
261 elog(DEBUG4, "relation created with OID %u", id);
262 }
263 do_end();
264 }
265 ;
266
267 Boot_InsertStmt:
268 INSERT_TUPLE optoideq
269 {
270 do_start();
271 if ($2)
272 elog(DEBUG4, "inserting row with oid %u", $2);
273 else
274 elog(DEBUG4, "inserting row");
275 num_columns_read = 0;
276 }
277 LPAREN boot_column_val_list RPAREN
278 {
279 if (num_columns_read != numattr)
280 elog(ERROR, "incorrect number of columns in row (expected %d, got %d)",
281 numattr, num_columns_read);
282 if (boot_reldesc == NULL)
283 elog(FATAL, "relation not open");
284 InsertOneTuple($2);
285 do_end();
286 }
287 ;
288
289 Boot_DeclareIndexStmt:
290 XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
291 {
292 IndexStmt *stmt = makeNode(IndexStmt);
293 Oid relationId;
294
295 do_start();
296
297 stmt->idxname = $3;
298 stmt->relation = makeRangeVar(NULL, $6, -1);
299 stmt->accessMethod = $8;
300 stmt->tableSpace = NULL;
301 stmt->indexParams = $10;
302 stmt->options = NIL;
303 stmt->whereClause = NULL;
304 stmt->excludeOpNames = NIL;
305 stmt->idxcomment = NULL;
306 stmt->indexOid = InvalidOid;
307 stmt->oldNode = InvalidOid;
308 stmt->unique = false;
309 stmt->primary = false;
310 stmt->isconstraint = false;
311 stmt->deferrable = false;
312 stmt->initdeferred = false;
313 stmt->transformed = false;
314 stmt->concurrent = false;
315 stmt->if_not_exists = false;
316
317 /* locks and races need not concern us in bootstrap mode */
318 relationId = RangeVarGetRelid(stmt->relation, NoLock,
319 false);
320
321 DefineIndex(relationId,
322 stmt,
323 $4,
324 false,
325 false,
326 false,
327 true, /* skip_build */
328 false);
329 do_end();
330 }
331 ;
332
333 Boot_DeclareUniqueIndexStmt:
334 XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
335 {
336 IndexStmt *stmt = makeNode(IndexStmt);
337 Oid relationId;
338
339 do_start();
340
341 stmt->idxname = $4;
342 stmt->relation = makeRangeVar(NULL, $7, -1);
343 stmt->accessMethod = $9;
344 stmt->tableSpace = NULL;
345 stmt->indexParams = $11;
346 stmt->options = NIL;
347 stmt->whereClause = NULL;
348 stmt->excludeOpNames = NIL;
349 stmt->idxcomment = NULL;
350 stmt->indexOid = InvalidOid;
351 stmt->oldNode = InvalidOid;
352 stmt->unique = true;
353 stmt->primary = false;
354 stmt->isconstraint = false;
355 stmt->deferrable = false;
356 stmt->initdeferred = false;
357 stmt->transformed = false;
358 stmt->concurrent = false;
359 stmt->if_not_exists = false;
360
361 /* locks and races need not concern us in bootstrap mode */
362 relationId = RangeVarGetRelid(stmt->relation, NoLock,
363 false);
364
365 DefineIndex(relationId,
366 stmt,
367 $5,
368 false,
369 false,
370 false,
371 true, /* skip_build */
372 false);
373 do_end();
374 }
375 ;
376
377 Boot_DeclareToastStmt:
378 XDECLARE XTOAST oidspec oidspec ON boot_ident
379 {
380 do_start();
381
382 BootstrapToastTable($6, $3, $4);
383 do_end();
384 }
385 ;
386
387 Boot_BuildIndsStmt:
388 XBUILD INDICES
389 {
390 do_start();
391 build_indices();
392 do_end();
393 }
394 ;
395
396
397 boot_index_params:
398 boot_index_params COMMA boot_index_param { $$ = lappend($1, $3); }
399 | boot_index_param { $$ = list_make1($1); }
400 ;
401
402 boot_index_param:
403 boot_ident boot_ident
404 {
405 IndexElem *n = makeNode(IndexElem);
406 n->name = $1;
407 n->expr = NULL;
408 n->indexcolname = NULL;
409 n->collation = NIL;
410 n->opclass = list_make1(makeString($2));
411 n->ordering = SORTBY_DEFAULT;
412 n->nulls_ordering = SORTBY_NULLS_DEFAULT;
413 $$ = n;
414 }
415 ;
416
417 optbootstrap:
418 XBOOTSTRAP { $$ = 1; }
419 | { $$ = 0; }
420 ;
421
422 optsharedrelation:
423 XSHARED_RELATION { $$ = 1; }
424 | { $$ = 0; }
425 ;
426
427 optwithoutoids:
428 XWITHOUT_OIDS { $$ = 1; }
429 | { $$ = 0; }
430 ;
431
432 optrowtypeoid:
433 XROWTYPE_OID oidspec { $$ = $2; }
434 | { $$ = InvalidOid; }
435 ;
436
437 boot_column_list:
438 boot_column_def
439 | boot_column_list COMMA boot_column_def
440 ;
441
442 boot_column_def:
443 boot_ident EQUALS boot_ident boot_column_nullness
444 {
445 if (++numattr > MAXATTR)
446 elog(FATAL, "too many columns");
447 DefineAttr($1, $3, numattr-1, $4);
448 }
449 ;
450
451 boot_column_nullness:
452 XFORCE XNOT XNULL { $$ = BOOTCOL_NULL_FORCE_NOT_NULL; }
453 | XFORCE XNULL { $$ = BOOTCOL_NULL_FORCE_NULL; }
454 | { $$ = BOOTCOL_NULL_AUTO; }
455 ;
456
457 oidspec:
458 boot_ident { $$ = atooid($1); }
459 ;
460
461 optoideq:
462 OBJ_ID EQUALS oidspec { $$ = $3; }
463 | { $$ = InvalidOid; }
464 ;
465
466 boot_column_val_list:
467 boot_column_val
468 | boot_column_val_list boot_column_val
469 | boot_column_val_list COMMA boot_column_val
470 ;
471
472 boot_column_val:
473 boot_ident
474 { InsertOneValue($1, num_columns_read++); }
475 | NULLVAL
476 { InsertOneNull(num_columns_read++); }
477 ;
478
479 boot_ident :
480 ID { $$ = yylval.str; }
481 ;
482 %%
483
484 #include "bootscanner.c"
485