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