1 %{
2 /*-------------------------------------------------------------------------
3  *
4  * syncrep_gram.y				- Parser for synchronous_standby_names
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/replication/syncrep_gram.y
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "replication/syncrep.h"
18 
19 /* Result of parsing is returned in one of these two variables */
20 SyncRepConfigData *syncrep_parse_result;
21 char	   *syncrep_parse_error_msg;
22 
23 static SyncRepConfigData *create_syncrep_config(const char *num_sync,
24 					List *members, uint8 syncrep_method);
25 
26 /*
27  * Bison doesn't allocate anything that needs to live across parser calls,
28  * so we can easily have it use palloc instead of malloc.  This prevents
29  * memory leaks if we error out during parsing.  Note this only works with
30  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
31  * if possible, so there's not really much problem anyhow, at least if
32  * you're building with gcc.
33  */
34 #define YYMALLOC palloc
35 #define YYFREE   pfree
36 
37 %}
38 
39 %expect 0
40 %name-prefix="syncrep_yy"
41 
42 %union
43 {
44 	char	   *str;
45 	List	   *list;
46 	SyncRepConfigData *config;
47 }
48 
49 %token <str> NAME NUM JUNK ANY FIRST
50 
51 %type <config> result standby_config
52 %type <list> standby_list
53 %type <str> standby_name
54 
55 %start result
56 
57 %%
58 result:
59 		standby_config				{ syncrep_parse_result = $1; }
60 	;
61 
62 standby_config:
63 		standby_list				{ $$ = create_syncrep_config("1", $1, SYNC_REP_PRIORITY); }
64 		| NUM '(' standby_list ')'		{ $$ = create_syncrep_config($1, $3, SYNC_REP_PRIORITY); }
65 		| ANY NUM '(' standby_list ')'		{ $$ = create_syncrep_config($2, $4, SYNC_REP_QUORUM); }
66 		| FIRST NUM '(' standby_list ')'		{ $$ = create_syncrep_config($2, $4, SYNC_REP_PRIORITY); }
67 	;
68 
69 standby_list:
70 		standby_name						{ $$ = list_make1($1); }
71 		| standby_list ',' standby_name		{ $$ = lappend($1, $3); }
72 	;
73 
74 standby_name:
75 		NAME						{ $$ = $1; }
76 		| NUM						{ $$ = $1; }
77 	;
78 %%
79 
80 static SyncRepConfigData *
81 create_syncrep_config(const char *num_sync, List *members, uint8 syncrep_method)
82 {
83 	SyncRepConfigData *config;
84 	int			size;
85 	ListCell   *lc;
86 	char	   *ptr;
87 
88 	/* Compute space needed for flat representation */
89 	size = offsetof(SyncRepConfigData, member_names);
foreach(lc,members)90 	foreach(lc, members)
91 	{
92 		char	   *standby_name = (char *) lfirst(lc);
93 
94 		size += strlen(standby_name) + 1;
95 	}
96 
97 	/* And transform the data into flat representation */
98 	config = (SyncRepConfigData *) palloc(size);
99 
100 	config->config_size = size;
101 	config->num_sync = atoi(num_sync);
102 	config->syncrep_method = syncrep_method;
103 	config->nmembers = list_length(members);
104 	ptr = config->member_names;
foreach(lc,members)105 	foreach(lc, members)
106 	{
107 		char	   *standby_name = (char *) lfirst(lc);
108 
109 		strcpy(ptr, standby_name);
110 		ptr += strlen(standby_name) + 1;
111 	}
112 
113 	return config;
114 }
115 
116 #include "syncrep_scanner.c"
117