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-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
69 6110 : do_start(void)
70 : {
71 6110 : Assert(CurrentMemoryContext == CurTransactionContext);
72 : /* First time through, create the per-line working context */
73 6110 : if (per_line_ctx == NULL)
74 1 : per_line_ctx = AllocSetContextCreate(CurTransactionContext,
75 : "bootstrap per-line processing",
76 : ALLOCSET_DEFAULT_SIZES);
77 6110 : MemoryContextSwitchTo(per_line_ctx);
78 6110 : }
79 :
80 :
81 : static void
82 6110 : do_end(void)
83 : {
84 : /* Reclaim memory allocated while processing this line */
85 6110 : MemoryContextSwitchTo(CurTransactionContext);
86 6110 : MemoryContextReset(per_line_ctx);
87 6110 : CHECK_FOR_INTERRUPTS(); /* allow SIGINT to kill bootstrap run */
88 6110 : if (isatty(0))
89 : {
90 0 : printf("bootstrap> ");
91 0 : fflush(stdout);
92 : }
93 6110 : }
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 58 : do_start();
157 58 : boot_openrel($2);
158 58 : do_end();
159 : }
160 : ;
161 :
162 : Boot_CloseStmt:
163 : XCLOSE boot_ident %prec low
164 : {
165 62 : do_start();
166 62 : closerel($2);
167 62 : do_end();
168 : }
169 : | XCLOSE %prec high
170 : {
171 0 : do_start();
172 0 : closerel(NULL);
173 0 : do_end();
174 : }
175 : ;
176 :
177 : Boot_CreateStmt:
178 : XCREATE boot_ident oidspec optbootstrap optsharedrelation optwithoutoids optrowtypeoid LPAREN
179 : {
180 62 : do_start();
181 62 : numattr = 0;
182 62 : 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 62 : do_end();
191 : }
192 : RPAREN
193 : {
194 : TupleDesc tupdesc;
195 : bool shared_relation;
196 : bool mapped_relation;
197 :
198 62 : do_start();
199 :
200 62 : tupdesc = CreateTupleDesc(numattr, !($6), attrtypes);
201 :
202 62 : 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 62 : mapped_relation = ($4 || shared_relation);
214 :
215 62 : if ($4)
216 : {
217 4 : if (boot_reldesc)
218 : {
219 0 : elog(DEBUG4, "create bootstrap: warning, open relation exists, closing first");
220 0 : closerel(NULL);
221 : }
222 :
223 8 : boot_reldesc = heap_create($2,
224 : PG_CATALOG_NAMESPACE,
225 : shared_relation ? GLOBALTABLESPACE_OID : 0,
226 4 : $3,
227 : InvalidOid,
228 : tupdesc,
229 : RELKIND_RELATION,
230 : RELPERSISTENCE_PERMANENT,
231 : shared_relation,
232 : mapped_relation,
233 : true);
234 4 : elog(DEBUG4, "bootstrap relation created");
235 : }
236 : else
237 : {
238 : Oid id;
239 :
240 174 : id = heap_create_with_catalog($2,
241 : PG_CATALOG_NAMESPACE,
242 : shared_relation ? GLOBALTABLESPACE_OID : 0,
243 58 : $3,
244 58 : $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 58 : elog(DEBUG4, "relation created with OID %u", id);
262 : }
263 62 : do_end();
264 : }
265 : ;
266 :
267 : Boot_InsertStmt:
268 : INSERT_TUPLE optoideq
269 : {
270 5738 : do_start();
271 5738 : if ($2)
272 3928 : elog(DEBUG4, "inserting row with oid %u", $2);
273 : else
274 1810 : elog(DEBUG4, "inserting row");
275 5738 : num_columns_read = 0;
276 : }
277 : LPAREN boot_column_val_list RPAREN
278 : {
279 5738 : if (num_columns_read != numattr)
280 0 : elog(ERROR, "incorrect number of columns in row (expected %d, got %d)",
281 : numattr, num_columns_read);
282 5738 : if (boot_reldesc == NULL)
283 0 : elog(FATAL, "relation not open");
284 5738 : InsertOneTuple($2);
285 5738 : 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 12 : IndexStmt *stmt = makeNode(IndexStmt);
293 : Oid relationId;
294 :
295 12 : do_start();
296 :
297 12 : stmt->idxname = $3;
298 12 : stmt->relation = makeRangeVar(NULL, $6, -1);
299 12 : stmt->accessMethod = $8;
300 12 : stmt->tableSpace = NULL;
301 12 : stmt->indexParams = $10;
302 12 : stmt->options = NIL;
303 12 : stmt->whereClause = NULL;
304 12 : stmt->excludeOpNames = NIL;
305 12 : stmt->idxcomment = NULL;
306 12 : stmt->indexOid = InvalidOid;
307 12 : stmt->oldNode = InvalidOid;
308 12 : stmt->unique = false;
309 12 : stmt->primary = false;
310 12 : stmt->isconstraint = false;
311 12 : stmt->deferrable = false;
312 12 : stmt->initdeferred = false;
313 12 : stmt->transformed = false;
314 12 : stmt->concurrent = false;
315 12 : stmt->if_not_exists = false;
316 :
317 : /* locks and races need not concern us in bootstrap mode */
318 12 : relationId = RangeVarGetRelid(stmt->relation, NoLock,
319 : false);
320 :
321 12 : DefineIndex(relationId,
322 : stmt,
323 12 : $4,
324 : false,
325 : false,
326 : false,
327 : true, /* skip_build */
328 : false);
329 12 : 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 103 : IndexStmt *stmt = makeNode(IndexStmt);
337 : Oid relationId;
338 :
339 103 : do_start();
340 :
341 103 : stmt->idxname = $4;
342 103 : stmt->relation = makeRangeVar(NULL, $7, -1);
343 103 : stmt->accessMethod = $9;
344 103 : stmt->tableSpace = NULL;
345 103 : stmt->indexParams = $11;
346 103 : stmt->options = NIL;
347 103 : stmt->whereClause = NULL;
348 103 : stmt->excludeOpNames = NIL;
349 103 : stmt->idxcomment = NULL;
350 103 : stmt->indexOid = InvalidOid;
351 103 : stmt->oldNode = InvalidOid;
352 103 : stmt->unique = true;
353 103 : stmt->primary = false;
354 103 : stmt->isconstraint = false;
355 103 : stmt->deferrable = false;
356 103 : stmt->initdeferred = false;
357 103 : stmt->transformed = false;
358 103 : stmt->concurrent = false;
359 103 : stmt->if_not_exists = false;
360 :
361 : /* locks and races need not concern us in bootstrap mode */
362 103 : relationId = RangeVarGetRelid(stmt->relation, NoLock,
363 : false);
364 :
365 103 : DefineIndex(relationId,
366 : stmt,
367 103 : $5,
368 : false,
369 : false,
370 : false,
371 : true, /* skip_build */
372 : false);
373 103 : do_end();
374 : }
375 : ;
376 :
377 : Boot_DeclareToastStmt:
378 : XDECLARE XTOAST oidspec oidspec ON boot_ident
379 : {
380 12 : do_start();
381 :
382 12 : BootstrapToastTable($6, $3, $4);
383 12 : do_end();
384 : }
385 : ;
386 :
387 : Boot_BuildIndsStmt:
388 : XBUILD INDICES
389 : {
390 1 : do_start();
391 1 : build_indices();
392 1 : do_end();
393 : }
394 : ;
395 :
396 :
397 : boot_index_params:
398 75 : boot_index_params COMMA boot_index_param { $$ = lappend($1, $3); }
399 115 : | boot_index_param { $$ = list_make1($1); }
400 : ;
401 :
402 : boot_index_param:
403 : boot_ident boot_ident
404 : {
405 190 : IndexElem *n = makeNode(IndexElem);
406 190 : n->name = $1;
407 190 : n->expr = NULL;
408 190 : n->indexcolname = NULL;
409 190 : n->collation = NIL;
410 190 : n->opclass = list_make1(makeString($2));
411 190 : n->ordering = SORTBY_DEFAULT;
412 190 : n->nulls_ordering = SORTBY_NULLS_DEFAULT;
413 190 : $$ = n;
414 : }
415 : ;
416 :
417 : optbootstrap:
418 4 : XBOOTSTRAP { $$ = 1; }
419 58 : | { $$ = 0; }
420 : ;
421 :
422 : optsharedrelation:
423 11 : XSHARED_RELATION { $$ = 1; }
424 51 : | { $$ = 0; }
425 : ;
426 :
427 : optwithoutoids:
428 23 : XWITHOUT_OIDS { $$ = 1; }
429 39 : | { $$ = 0; }
430 : ;
431 :
432 : optrowtypeoid:
433 9 : XROWTYPE_OID oidspec { $$ = $2; }
434 53 : | { $$ = 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 515 : if (++numattr > MAXATTR)
446 0 : elog(FATAL, "too many columns");
447 515 : DefineAttr($1, $3, numattr-1, $4);
448 : }
449 : ;
450 :
451 : boot_column_nullness:
452 18 : XFORCE XNOT XNULL { $$ = BOOTCOL_NULL_FORCE_NOT_NULL; }
453 0 : | XFORCE XNULL { $$ = BOOTCOL_NULL_FORCE_NULL; }
454 497 : | { $$ = BOOTCOL_NULL_AUTO; }
455 : ;
456 :
457 : oidspec:
458 4138 : boot_ident { $$ = atooid($1); }
459 : ;
460 :
461 : optoideq:
462 3928 : OBJ_ID EQUALS oidspec { $$ = $3; }
463 1810 : | { $$ = 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 91074 : { InsertOneValue($1, num_columns_read++); }
475 : | NULLVAL
476 23450 : { InsertOneNull(num_columns_read++); }
477 : ;
478 :
479 : boot_ident :
480 97161 : ID { $$ = yylval.str; }
481 : ;
482 : %%
483 :
484 : #include "bootscanner.c"
|