summaryrefslogtreecommitdiffstats
path: root/src/backend/replication/syncrep_gram.y
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/replication/syncrep_gram.y')
-rw-r--r--src/backend/replication/syncrep_gram.y116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/backend/replication/syncrep_gram.y b/src/backend/replication/syncrep_gram.y
new file mode 100644
index 0000000..88d95f2
--- /dev/null
+++ b/src/backend/replication/syncrep_gram.y
@@ -0,0 +1,116 @@
+%{
+/*-------------------------------------------------------------------------
+ *
+ * syncrep_gram.y - Parser for synchronous_standby_names
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/replication/syncrep_gram.y
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "replication/syncrep.h"
+
+/* Result of parsing is returned in one of these two variables */
+SyncRepConfigData *syncrep_parse_result;
+char *syncrep_parse_error_msg;
+
+static SyncRepConfigData *create_syncrep_config(const char *num_sync,
+ List *members, uint8 syncrep_method);
+
+/*
+ * Bison doesn't allocate anything that needs to live across parser calls,
+ * so we can easily have it use palloc instead of malloc. This prevents
+ * memory leaks if we error out during parsing. Note this only works with
+ * bison >= 2.0. However, in bison 1.875 the default is to use alloca()
+ * if possible, so there's not really much problem anyhow, at least if
+ * you're building with gcc.
+ */
+#define YYMALLOC palloc
+#define YYFREE pfree
+
+%}
+
+%expect 0
+%name-prefix="syncrep_yy"
+
+%union
+{
+ char *str;
+ List *list;
+ SyncRepConfigData *config;
+}
+
+%token <str> NAME NUM JUNK ANY FIRST
+
+%type <config> result standby_config
+%type <list> standby_list
+%type <str> standby_name
+
+%start result
+
+%%
+result:
+ standby_config { syncrep_parse_result = $1; }
+ ;
+
+standby_config:
+ standby_list { $$ = create_syncrep_config("1", $1, SYNC_REP_PRIORITY); }
+ | NUM '(' standby_list ')' { $$ = create_syncrep_config($1, $3, SYNC_REP_PRIORITY); }
+ | ANY NUM '(' standby_list ')' { $$ = create_syncrep_config($2, $4, SYNC_REP_QUORUM); }
+ | FIRST NUM '(' standby_list ')' { $$ = create_syncrep_config($2, $4, SYNC_REP_PRIORITY); }
+ ;
+
+standby_list:
+ standby_name { $$ = list_make1($1); }
+ | standby_list ',' standby_name { $$ = lappend($1, $3); }
+ ;
+
+standby_name:
+ NAME { $$ = $1; }
+ | NUM { $$ = $1; }
+ ;
+%%
+
+static SyncRepConfigData *
+create_syncrep_config(const char *num_sync, List *members, uint8 syncrep_method)
+{
+ SyncRepConfigData *config;
+ int size;
+ ListCell *lc;
+ char *ptr;
+
+ /* Compute space needed for flat representation */
+ size = offsetof(SyncRepConfigData, member_names);
+ foreach(lc, members)
+ {
+ char *standby_name = (char *) lfirst(lc);
+
+ size += strlen(standby_name) + 1;
+ }
+
+ /* And transform the data into flat representation */
+ config = (SyncRepConfigData *) palloc(size);
+
+ config->config_size = size;
+ config->num_sync = atoi(num_sync);
+ config->syncrep_method = syncrep_method;
+ config->nmembers = list_length(members);
+ ptr = config->member_names;
+ foreach(lc, members)
+ {
+ char *standby_name = (char *) lfirst(lc);
+
+ strcpy(ptr, standby_name);
+ ptr += strlen(standby_name) + 1;
+ }
+
+ return config;
+}
+
+#include "syncrep_scanner.c"