mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-22 22:56:29 +00:00
Add "repmgr bdr register"
This commit is contained in:
@@ -26,7 +26,8 @@ include Makefile.global
|
||||
|
||||
$(info Building against PostgreSQL $(MAJORVERSION))
|
||||
|
||||
REPMGR_CLIENT_OBJS = repmgr-client.o repmgr-action-primary.o repmgr-action-standby.o repmgr-action-cluster.o \
|
||||
REPMGR_CLIENT_OBJS = repmgr-client.o \
|
||||
repmgr-action-primary.o repmgr-action-standby.o repmgr-action-bdr.o repmgr-action-cluster.o \
|
||||
config.o log.o strutil.o dbutils.o dirutil.o compat.o controldata.o
|
||||
REPMGRD_OBJS = repmgrd.o config.o log.o dbutils.o strutil.o
|
||||
|
||||
@@ -52,9 +53,10 @@ maintainer-clean: additional-maintainer-clean
|
||||
|
||||
additional-clean:
|
||||
rm -f repmgr-client.o
|
||||
rm -f repmgr-action-cluster.o
|
||||
rm -f repmgr-action-primary.o
|
||||
rm -f repmgr-action-standby.o
|
||||
rm -f repmgr-action-bdr.o
|
||||
rm -f repmgr-action-cluster.o
|
||||
rm -f repmgrd.o
|
||||
rm -f compat.o
|
||||
rm -f config.o
|
||||
|
||||
66
README.md
66
README.md
@@ -37,6 +37,8 @@ Currently available:
|
||||
repmgr standby promote
|
||||
repmgr standby follow
|
||||
|
||||
repmgr bdr register
|
||||
|
||||
repmgr cluster event [--all] [--node-id] [--node-name] [--event] [--event-matching]
|
||||
|
||||
|
||||
@@ -63,3 +65,67 @@ and vice-versa, e.g. to avoid hard-coding things like a node's
|
||||
upstream ID which might change.
|
||||
|
||||
TODO: possibly add a config file conversion script/function.
|
||||
|
||||
Generating event notifications with repmgr/repmgrd
|
||||
--------------------------------------------------
|
||||
|
||||
Each time `repmgr` or `repmgrd` perform a significant event, a record
|
||||
of that event is written into the `repl_events` table together with
|
||||
a timestamp, an indication of failure or success, and further details
|
||||
if appropriate. This is useful for gaining an overview of events
|
||||
affecting the replication cluster. However note that this table has
|
||||
advisory character and should be used in combination with the `repmgr`
|
||||
and PostgreSQL logs to obtain details of any events.
|
||||
|
||||
Example output after a master was registered and a standby cloned
|
||||
and registered:
|
||||
|
||||
repmgr=# SELECT * from repmgr_test.repl_events ;
|
||||
node_id | event | successful | event_timestamp | details
|
||||
---------+------------------+------------+-------------------------------+-------------------------------------------------------------------------------------
|
||||
1 | master_register | t | 2016-01-08 15:04:39.781733+09 |
|
||||
2 | standby_clone | t | 2016-01-08 15:04:49.530001+09 | Cloned from host 'repmgr_node1', port 5432; backup method: pg_basebackup; --force: N
|
||||
2 | standby_register | t | 2016-01-08 15:04:50.621292+09 |
|
||||
(3 rows)
|
||||
|
||||
Additionally, event notifications can be passed to a user-defined program
|
||||
or script which can take further action, e.g. send email notifications.
|
||||
This is done by setting the `event_notification_command` parameter in
|
||||
`repmgr.conf`.
|
||||
|
||||
This parameter accepts the following format placeholders:
|
||||
|
||||
%n - node ID
|
||||
%e - event type
|
||||
%s - success (1 or 0)
|
||||
%t - timestamp
|
||||
%d - details
|
||||
|
||||
The values provided for "%t" and "%d" will probably contain spaces,
|
||||
so should be quoted in the provided command configuration, e.g.:
|
||||
|
||||
event_notification_command='/path/to/some/script %n %e %s "%t" "%d"'
|
||||
|
||||
Additionally the following format placeholders are available for the even
|
||||
type `bdr_failover`:
|
||||
|
||||
%c - conninfo string of the next available node
|
||||
%a - name of the next available node
|
||||
|
||||
These should always be quoted.
|
||||
|
||||
By default, all notification type will be passed to the designated script;
|
||||
the notification types can be filtered to explicitly named ones:
|
||||
|
||||
event_notifications=master_register,standby_register
|
||||
|
||||
The following event types are available:
|
||||
|
||||
...
|
||||
* `bdr_failover`
|
||||
* `bdr_register`
|
||||
* `bdr_unregister`
|
||||
|
||||
Note that under some circumstances (e.g. no replication cluster master could
|
||||
be located), it will not be possible to write an entry into the `repl_events`
|
||||
table, in which case `event_notification_command` can serve as a fallback.
|
||||
|
||||
111
dbutils.c
111
dbutils.c
@@ -47,6 +47,33 @@ parse_lsn(const char *str)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wrap query with appropriate DDL function, if required.
|
||||
*/
|
||||
void
|
||||
wrap_ddl_query(PQExpBufferData *query_buf, int replication_type, const char *fmt, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
char buf[MAXLEN];
|
||||
|
||||
if (replication_type == REPLICATION_TYPE_BDR)
|
||||
{
|
||||
appendPQExpBuffer(query_buf, "SELECT bdr.bdr_replicate_ddl_command($repmgr$");
|
||||
}
|
||||
|
||||
va_start(arglist, fmt);
|
||||
vsnprintf(buf, MAXLEN, fmt, arglist);
|
||||
va_end(arglist);
|
||||
|
||||
appendPQExpBuffer(query_buf, "%s", buf);
|
||||
|
||||
if (replication_type == REPLICATION_TYPE_BDR)
|
||||
{
|
||||
appendPQExpBuffer(query_buf, "$repmgr$)");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ==================== */
|
||||
/* Connection functions */
|
||||
/* ==================== */
|
||||
@@ -1517,6 +1544,7 @@ update_node_record(PGconn *conn, char *repmgr_action, t_node_info *node_info)
|
||||
return _create_update_node_record(conn, "update", node_info);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
_create_update_node_record(PGconn *conn, char *action, t_node_info *node_info)
|
||||
{
|
||||
@@ -2793,7 +2821,7 @@ is_bdr_repmgr(PGconn *conn)
|
||||
|
||||
|
||||
bool
|
||||
is_table_in_bdr_replication_set(PGconn *conn, char *tablename, char *set)
|
||||
is_table_in_bdr_replication_set(PGconn *conn, const char *tablename, const char *set)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
@@ -2829,10 +2857,10 @@ is_table_in_bdr_replication_set(PGconn *conn, char *tablename, char *set)
|
||||
|
||||
|
||||
bool
|
||||
add_table_to_bdr_replication_set(PGconn *conn, char *tablename, char *set)
|
||||
add_table_to_bdr_replication_set(PGconn *conn, const char *tablename, const char *set)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
PGresult *res;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
@@ -2861,3 +2889,80 @@ add_table_to_bdr_replication_set(PGconn *conn, char *tablename, char *set)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
bdr_node_exists(PGconn *conn, const char *node_name)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
bool node_exists;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&query,
|
||||
"SELECT COUNT(*)"
|
||||
" FROM bdr.bdr_nodes"
|
||||
" WHERE node_name = '%s'",
|
||||
node_name);
|
||||
|
||||
res = PQexec(conn, query.data);
|
||||
termPQExpBuffer(&query);
|
||||
|
||||
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
node_exists = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
node_exists = atoi(PQgetvalue(res, 0, 0)) == 1 ? true : false;
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
||||
return node_exists;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
add_extension_tables_to_bdr_replication_set(PGconn *conn)
|
||||
{
|
||||
PQExpBufferData query;
|
||||
PGresult *res;
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(
|
||||
&query,
|
||||
" SELECT c.relname "
|
||||
" FROM pg_class c "
|
||||
"INNER JOIN pg_namespace n "
|
||||
" ON c.relnamespace = n.oid "
|
||||
" WHERE n.nspname = 'repmgr' "
|
||||
" AND c.relkind = 'r' ");
|
||||
|
||||
res = PQexec(conn, query.data);
|
||||
termPQExpBuffer(&query);
|
||||
|
||||
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
{
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PQntuples(res); i++)
|
||||
{
|
||||
add_table_to_bdr_replication_set(
|
||||
conn,
|
||||
PQgetvalue(res, i, 0),
|
||||
"repmgr");
|
||||
}
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -148,6 +148,8 @@ typedef struct s_connection_user
|
||||
|
||||
XLogRecPtr parse_lsn(const char *str);
|
||||
|
||||
extern void wrap_ddl_query(PQExpBufferData *query_buf, int replication_type, const char *fmt, ...)
|
||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
|
||||
|
||||
/* connection functions */
|
||||
PGconn *establish_db_connection(const char *conninfo,
|
||||
@@ -268,8 +270,10 @@ XLogRecPtr get_last_wal_receive_location(PGconn *conn);
|
||||
|
||||
bool is_bdr_db(PGconn *conn);
|
||||
bool is_bdr_repmgr(PGconn *conn);
|
||||
bool is_table_in_bdr_replication_set(PGconn *conn, char *tablename, char *set);
|
||||
bool add_table_to_bdr_replication_set(PGconn *conn, char *tablename, char *set);
|
||||
bool is_table_in_bdr_replication_set(PGconn *conn, const char *tablename, const char *set);
|
||||
bool add_table_to_bdr_replication_set(PGconn *conn, const char *tablename, const char *set);
|
||||
bool bdr_node_exists(PGconn *conn, const char *node_name);
|
||||
void add_extension_tables_to_bdr_replication_set(PGconn *conn);
|
||||
|
||||
#endif /* dbutils.h */
|
||||
|
||||
|
||||
221
repmgr-action-bdr.c
Normal file
221
repmgr-action-bdr.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* repmgr-action-standby.c
|
||||
*
|
||||
* Implements BDR-related actions for the repmgr command line utility
|
||||
*
|
||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||
*/
|
||||
|
||||
#include "repmgr.h"
|
||||
|
||||
#include "repmgr-client-global.h"
|
||||
#include "repmgr-action-bdr.h"
|
||||
|
||||
|
||||
/*
|
||||
* do_bdr_register()
|
||||
*
|
||||
* As each BDR node is its own master, registering a BDR node
|
||||
* will create the repmgr metadata schema if necessary.
|
||||
*/
|
||||
void
|
||||
do_bdr_register(void)
|
||||
{
|
||||
PGconn *conn = NULL;
|
||||
ExtensionStatus extension_status;
|
||||
t_node_info node_info = T_NODE_INFO_INITIALIZER;
|
||||
RecordStatus record_status;
|
||||
PQExpBufferData event_details;
|
||||
bool success = true;
|
||||
|
||||
/* sanity-check configuration for BDR-compatability */
|
||||
if (config_file_options.replication_type != REPLICATION_TYPE_BDR)
|
||||
{
|
||||
log_error(_("cannot run BDR REGISTER on a non-BDR node"));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
conn = establish_db_connection(config_file_options.conninfo, true);
|
||||
|
||||
if (!is_bdr_db(conn))
|
||||
{
|
||||
/* TODO: name database */
|
||||
log_error(_("database is not BDR-enabled"));
|
||||
log_hint(_("when using repmgr with BDR, the repmgr schema must be stored in the BDR database"));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/* check whether repmgr extension exists, and that any other nodes are BDR */
|
||||
extension_status = get_repmgr_extension_status(conn);
|
||||
|
||||
if (extension_status == REPMGR_UNKNOWN)
|
||||
{
|
||||
log_error(_("unable to determine status of \"repmgr\" extension"));
|
||||
PQfinish(conn);
|
||||
}
|
||||
|
||||
|
||||
if (extension_status == REPMGR_UNAVAILABLE)
|
||||
{
|
||||
log_error(_("\"repmgr\" extension is not available"));
|
||||
PQfinish(conn);
|
||||
}
|
||||
|
||||
if (extension_status == REPMGR_INSTALLED)
|
||||
{
|
||||
if (!is_bdr_repmgr(conn))
|
||||
{
|
||||
log_error(_("repmgr metadatabase contains records for non-BDR nodes"));
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//log_info(_("bdr register: creating database objects inside the %s schema"),
|
||||
// get_repmgr_schema());
|
||||
|
||||
begin_transaction(conn);
|
||||
|
||||
if (!create_repmgr_extension(conn))
|
||||
{
|
||||
log_error(_("unable to create repmgr extension - see preceding error message(s); aborting"));
|
||||
rollback_transaction(conn);
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
commit_transaction(conn);
|
||||
}
|
||||
|
||||
/* check for a matching BDR node */
|
||||
{
|
||||
bool node_exists = bdr_node_exists(conn, config_file_options.node_name);
|
||||
|
||||
if (node_exists == false)
|
||||
{
|
||||
log_error(_("no BDR node with node_name '%s' found"), config_file_options.node_name);
|
||||
log_hint(_("'node_name' in repmgr.conf must match 'node_name' in bdr.bdr_nodes\n"));
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
}
|
||||
|
||||
initPQExpBuffer(&event_details);
|
||||
|
||||
begin_transaction(conn);
|
||||
|
||||
/*
|
||||
* we'll check if a record exists (even if the schema was just created),
|
||||
* as there's a faint chance of a race condition
|
||||
*/
|
||||
|
||||
record_status = get_node_record(conn, config_file_options.node_id, &node_info);
|
||||
|
||||
/* Update internal node record */
|
||||
|
||||
node_info.type = BDR;
|
||||
node_info.node_id = config_file_options.node_id;
|
||||
node_info.upstream_node_id = NO_UPSTREAM_NODE;
|
||||
node_info.active = true;
|
||||
node_info.priority = config_file_options.priority;
|
||||
|
||||
strncpy(node_info.node_name, config_file_options.node_name, MAXLEN);
|
||||
strncpy(node_info.location, config_file_options.location, MAXLEN);
|
||||
strncpy(node_info.conninfo, config_file_options.conninfo, MAXLEN);
|
||||
|
||||
if (record_status == RECORD_FOUND)
|
||||
{
|
||||
bool node_updated;
|
||||
/*
|
||||
* At this point we will have established there are no non-BDR records,
|
||||
* so no need to verify the node type
|
||||
*/
|
||||
if (!runtime_options.force)
|
||||
{
|
||||
log_error(_("this node is already registered"));
|
||||
log_hint(_("use -F/--force to overwrite the existing node record"));
|
||||
rollback_transaction(conn);
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
/*
|
||||
* don't permit changing the node name - this must match the
|
||||
* BDR node name set when the node was registered.
|
||||
*/
|
||||
|
||||
if (strncmp(node_info.node_name, config_file_options.node_name, MAXLEN) != 0)
|
||||
{
|
||||
log_error(_("a record for node %i is already registered with node_name '%s'"),
|
||||
config_file_options.node_id, node_info.node_name);
|
||||
log_hint(_("node_name configured in repmgr.conf is '%s'"), config_file_options.node_name);
|
||||
|
||||
rollback_transaction(conn);
|
||||
PQfinish(conn);
|
||||
exit(ERR_BAD_CONFIG);
|
||||
}
|
||||
|
||||
node_updated = update_node_record(conn, "bdr register", &node_info);
|
||||
|
||||
if (node_updated == true)
|
||||
{
|
||||
appendPQExpBuffer(&event_details, _("node record updated for node '%s' (%i)"),
|
||||
config_file_options.node_name, config_file_options.node_id);
|
||||
log_verbose(LOG_NOTICE, "%s\n", event_details.data);
|
||||
}
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* create new node record */
|
||||
bool node_created = create_node_record(conn, "bdr register", &node_info);
|
||||
|
||||
if (node_created == true)
|
||||
{
|
||||
appendPQExpBuffer(&event_details,
|
||||
_("node record created for node '%s' (ID: %i)"),
|
||||
config_file_options.node_name, config_file_options.node_id);
|
||||
log_notice("%s", event_details.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (success == false)
|
||||
{
|
||||
rollback_transaction(conn);
|
||||
PQfinish(conn);
|
||||
exit(ERR_DB_QUERY);
|
||||
}
|
||||
|
||||
commit_transaction(conn);
|
||||
/* Log the event */
|
||||
create_event_notification(
|
||||
conn,
|
||||
&config_file_options,
|
||||
config_file_options.node_id,
|
||||
"bdr_register",
|
||||
true,
|
||||
event_details.data);
|
||||
|
||||
termPQExpBuffer(&event_details);
|
||||
|
||||
PQfinish(conn);
|
||||
|
||||
log_notice(_("BDR node %i registered (conninfo: %s)"),
|
||||
config_file_options.node_id, config_file_options.conninfo);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
do_bdr_unregister(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
13
repmgr-action-bdr.h
Normal file
13
repmgr-action-bdr.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* repmgr-action-bdr.h
|
||||
* Copyright (c) 2ndQuadrant, 2010-2017
|
||||
*/
|
||||
|
||||
#ifndef _REPMGR_ACTION_BDR_H_
|
||||
#define _REPMGR_ACTION_BDR_H_
|
||||
|
||||
extern void do_bdr_register(void);
|
||||
extern void do_bdr_unregister(void);
|
||||
|
||||
|
||||
#endif /* _REPMGR_ACTION_BDR_H_ */
|
||||
@@ -33,4 +33,4 @@ typedef struct
|
||||
#define T_CONFIGFILE_LIST_INITIALIZER { 0, 0, NULL }
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* _REPMGR_ACTION_STANDBY_H_ */
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "repmgr-client-global.h"
|
||||
#include "repmgr-action-primary.h"
|
||||
#include "repmgr-action-standby.h"
|
||||
#include "repmgr-action-bdr.h"
|
||||
|
||||
#include "repmgr-action-cluster.h"
|
||||
|
||||
#include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */
|
||||
@@ -579,6 +581,7 @@ main(int argc, char **argv)
|
||||
else if (strcasecmp(repmgr_action, "UNREGISTER") == 0)
|
||||
action = PRIMARY_UNREGISTER;
|
||||
}
|
||||
|
||||
else if (strcasecmp(repmgr_node_type, "STANDBY") == 0)
|
||||
{
|
||||
if (strcasecmp(repmgr_action, "CLONE") == 0)
|
||||
@@ -599,6 +602,14 @@ main(int argc, char **argv)
|
||||
action = STANDBY_RESTORE_CONFIG;
|
||||
}
|
||||
|
||||
else if (strcasecmp(repmgr_node_type, "BDR") == 0)
|
||||
{
|
||||
if (strcasecmp(repmgr_action, "REGISTER") == 0)
|
||||
action = BDR_REGISTER;
|
||||
else if (strcasecmp(repmgr_action, "UNREGISTER") == 0)
|
||||
action = BDR_UNREGISTER;
|
||||
}
|
||||
|
||||
else if (strcasecmp(repmgr_node_type, "CLUSTER") == 0)
|
||||
{
|
||||
if (strcasecmp(repmgr_action, "EVENT") == 0)
|
||||
@@ -845,6 +856,7 @@ main(int argc, char **argv)
|
||||
|
||||
switch (action)
|
||||
{
|
||||
/* PRIMARY */
|
||||
case PRIMARY_REGISTER:
|
||||
do_primary_register();
|
||||
break;
|
||||
@@ -852,6 +864,7 @@ main(int argc, char **argv)
|
||||
do_primary_unregister();
|
||||
break;
|
||||
|
||||
/* STANDBY */
|
||||
case STANDBY_CLONE:
|
||||
do_standby_clone();
|
||||
break;
|
||||
@@ -877,6 +890,15 @@ main(int argc, char **argv)
|
||||
do_standby_restore_config();
|
||||
break;
|
||||
|
||||
/* BDR */
|
||||
case BDR_REGISTER:
|
||||
do_bdr_register();
|
||||
break;
|
||||
case BDR_UNREGISTER:
|
||||
do_bdr_unregister();
|
||||
break;
|
||||
|
||||
/* CLUSTER */
|
||||
case CLUSTER_EVENT:
|
||||
do_cluster_event();
|
||||
break;
|
||||
@@ -1336,14 +1358,14 @@ create_repmgr_extension(PGconn *conn)
|
||||
/* 4. Create extension */
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
"CREATE EXTENSION repmgr");
|
||||
wrap_ddl_query(&query, config_file_options.replication_type,
|
||||
"CREATE EXTENSION repmgr");
|
||||
|
||||
res = PQexec(schema_create_conn, query.data);
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
if ((PQresultStatus(res) != PGRES_COMMAND_OK && PQresultStatus(res) != PGRES_TUPLES_OK))
|
||||
{
|
||||
log_error(_("unable to create \"repmgr\" extension:\n %s"),
|
||||
PQerrorMessage(schema_create_conn));
|
||||
@@ -1357,14 +1379,21 @@ create_repmgr_extension(PGconn *conn)
|
||||
|
||||
PQclear(res);
|
||||
|
||||
/* For BDR, we'll need to add the repmgr extension tables to a replication set */
|
||||
if (config_file_options.replication_type == REPLICATION_TYPE_BDR)
|
||||
{
|
||||
add_extension_tables_to_bdr_replication_set(conn);
|
||||
}
|
||||
|
||||
/* 5. If not superuser, grant usage */
|
||||
if (is_superuser == false)
|
||||
{
|
||||
initPQExpBuffer(&query);
|
||||
|
||||
appendPQExpBuffer(&query,
|
||||
"GRANT USAGE ON SCHEMA repmgr TO %s",
|
||||
userinfo.username);
|
||||
wrap_ddl_query(&query, config_file_options.replication_type,
|
||||
"GRANT USAGE ON SCHEMA repmgr TO %s",
|
||||
userinfo.username);
|
||||
|
||||
res = PQexec(schema_create_conn, query.data);
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
@@ -1382,9 +1411,10 @@ create_repmgr_extension(PGconn *conn)
|
||||
}
|
||||
|
||||
initPQExpBuffer(&query);
|
||||
appendPQExpBuffer(&query,
|
||||
"GRANT ALL ON ALL TABLES IN SCHEMA repmgr TO %s",
|
||||
userinfo.username);
|
||||
wrap_ddl_query(&query, config_file_options.replication_type,
|
||||
"GRANT ALL ON ALL TABLES IN SCHEMA repmgr TO %s",
|
||||
userinfo.username);
|
||||
|
||||
res = PQexec(schema_create_conn, query.data);
|
||||
|
||||
termPQExpBuffer(&query);
|
||||
|
||||
Reference in New Issue
Block a user