/* *Iftheserverispromoted,thereisnowaytousethecurrentsetup *again.Warntheuserthatanewreplicationsetupshouldbedonebefore *tryingagain.
*/ if (recovery_ended)
{
pg_log_warning("failed after the end of recovery");
pg_log_warning_hint("The target server cannot be used as a physical replica anymore. " "You must recreate the physical replica before continuing.");
}
for (int i = 0; i < num_dbs; i++)
{ struct LogicalRepInfo *dbinfo = &dbinfos.dbinfo[i];
if (dbinfo->made_publication || dbinfo->made_replslot)
{
PGconn *conn;
conn = connect_database(dbinfo->pubconninfo, false); if (conn != NULL)
{ if (dbinfo->made_publication)
drop_publication(conn, dbinfo->pubname, dbinfo->dbname,
&dbinfo->made_publication); if (dbinfo->made_replslot)
drop_replication_slot(conn, dbinfo, dbinfo->replslotname);
disconnect_database(conn, false);
} else
{ /* *Ifaconnectioncouldnotbeestablished,informtheuser *thatsomeobjectswereleftonprimaryandshouldbe *removedbeforetryingagain.
*/ if (dbinfo->made_publication)
{
pg_log_warning("publication \"%s\" created in database \"%s\" on primary was left behind",
dbinfo->pubname,
dbinfo->dbname);
pg_log_warning_hint("Drop this publication before trying again.");
} if (dbinfo->made_replslot)
{
pg_log_warning("replication slot \"%s\" created in database \"%s\" on primary was left behind",
dbinfo->replslotname,
dbinfo->dbname);
pg_log_warning_hint("Drop this replication slot soon to avoid retention of WAL files.");
}
}
}
}
if (standby_running)
stop_standby_server(subscriber_dir);
}
staticvoid
usage(void)
{
printf(_("%s creates a new logical replica from a standby server.\n\n"),
progname);
printf(_("Usage:\n"));
printf(_(" %s [OPTION]...\n"), progname);
printf(_("\nOptions:\n"));
printf(_(" -a, --all create subscriptions for all databases except template\n" " databases and databases that don't allow connections\n"));
printf(_(" -d, --database=DBNAME database in which to create a subscription\n"));
printf(_(" -D, --pgdata=DATADIR location for the subscriber data directory\n"));
printf(_(" -n, --dry-run dry run, just show what would be done\n"));
printf(_(" -p, --subscriber-port=PORT subscriber port number (default %s)\n"), DEFAULT_SUB_PORT);
printf(_(" -P, --publisher-server=CONNSTR publisher connection string\n"));
printf(_(" -s, --socketdir=DIR socket directory to use (default current dir.)\n"));
printf(_(" -t, --recovery-timeout=SECS seconds to wait for recovery to end\n"));
printf(_(" -T, --enable-two-phase enable two-phase commit for all subscriptions\n"));
printf(_(" -U, --subscriber-username=NAME user name for subscriber connection\n"));
printf(_(" -v, --verbose output verbose messages\n"));
printf(_(" --clean=OBJECTTYPE drop all objects of the specified type from specified\n" " databases on the subscriber; accepts: \"%s\"\n"), "publications");
printf(_(" --config-file=FILENAME use specified main server configuration\n" " file when running target cluster\n"));
printf(_(" --publication=NAME publication name\n"));
printf(_(" --replication-slot=NAME replication slot name\n"));
printf(_(" --subscription=NAME subscription name\n"));
printf(_(" -V, --version output version information, then exit\n"));
printf(_(" -?, --help show this help, then exit\n"));
printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
}
if (find_my_exec(argv0, full_path) < 0)
strlcpy(full_path, progname, sizeof(full_path));
if (ret == -1)
pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
progname, "pg_createsubscriber", full_path); else
pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s",
progname, full_path, "pg_createsubscriber");
}
pg_log_debug("%s path is: %s", progname, exec_path);
pg_log_info("getting system identifier from publisher");
conn = connect_database(conninfo, true);
res = PQexec(conn, "SELECT system_identifier FROM pg_catalog.pg_control_system()"); if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("could not get system identifier: %s",
PQresultErrorMessage(res));
disconnect_database(conn, true);
} if (PQntuples(res) != 1)
{
pg_log_error("could not get system identifier: got %d rows, expected %d row",
PQntuples(res), 1);
disconnect_database(conn, true);
}
if (dry_run)
pg_log_info("dry-run: would set system identifier to %" PRIu64 " on subscriber",
cf->system_identifier); else
{
update_controlfile(subscriber_dir, cf, true);
pg_log_info("system identifier is %" PRIu64 " on subscriber",
cf->system_identifier);
}
if (dry_run)
pg_log_info("dry-run: would run pg_resetwal on the subscriber"); else
pg_log_info("running pg_resetwal on the subscriber");
pg_log_debug("pg_resetwal command is: %s", cmd_str);
if (!dry_run)
{ int rc = system(cmd_str);
if (rc == 0)
pg_log_info("successfully reset WAL on the subscriber"); else
pg_fatal("could not reset WAL on subscriber: %s", wait_result_to_str(rc));
}
char *wal_level; int max_repslots; int cur_repslots; int max_walsenders; int cur_walsenders; int max_prepared_transactions; char *max_slot_wal_keep_size;
/* *Iftheprimaryserverisinrecovery(i.e.cascadingreplication), *objects(publication)cannotbecreatedbecauseitisreadonly.
*/ if (server_is_in_recovery(conn))
{
pg_log_error("primary server cannot be in recovery");
disconnect_database(conn, true);
}
/*------------------------------------------------------------------------ *Logicalreplicationrequiresafewparameterstobesetonpublisher. *Sincetheseparametersarenotarequirementforphysicalreplication, *weshouldcheckittomakesureitwon'tfail. * *-wal_level=logical *-max_replication_slots>=current+numberofdbstobeconverted *-max_wal_senders>=current+numberofdbstobeconverted *-max_slot_wal_keep_size=-1(topreventdeletionofrequiredWALfiles) *-----------------------------------------------------------------------
*/
res = PQexec(conn, "SELECT pg_catalog.current_setting('wal_level')," " pg_catalog.current_setting('max_replication_slots')," " (SELECT count(*) FROM pg_catalog.pg_replication_slots)," " pg_catalog.current_setting('max_wal_senders')," " (SELECT count(*) FROM pg_catalog.pg_stat_activity WHERE backend_type = 'walsender')," " pg_catalog.current_setting('max_prepared_transactions')," " pg_catalog.current_setting('max_slot_wal_keep_size')");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("could not obtain publisher settings: %s",
PQresultErrorMessage(res));
disconnect_database(conn, true);
}
if (max_repslots - cur_repslots < num_dbs)
{
pg_log_error("publisher requires %d replication slots, but only %d remain",
num_dbs, max_repslots - cur_repslots);
pg_log_error_hint("Increase the configuration parameter \"%s\" to at least %d.", "max_replication_slots", cur_repslots + num_dbs);
failed = true;
}
if (max_walsenders - cur_walsenders < num_dbs)
{
pg_log_error("publisher requires %d WAL sender processes, but only %d remain",
num_dbs, max_walsenders - cur_walsenders);
pg_log_error_hint("Increase the configuration parameter \"%s\" to at least %d.", "max_wal_senders", cur_walsenders + num_dbs);
failed = true;
}
if (max_prepared_transactions != 0 && !dbinfos.two_phase)
{
pg_log_warning("two_phase option will not be enabled for replication slots");
pg_log_warning_detail("Subscriptions will be created with the two_phase option disabled. " "Prepared transactions will be replicated at COMMIT PREPARED.");
pg_log_warning_hint("You can use the command-line option --enable-two-phase to enable two_phase.");
}
/* *Indry-runmode,validate'max_slot_wal_keep_size'.Ifthisparameter *issettoanon-defaultvalue,itmaycausereplicationfailuresdueto *requiredWALfilesbeingprematurelyremoved.
*/ if (dry_run && (strcmp(max_slot_wal_keep_size, "-1") != 0))
{
pg_log_warning("required WAL could be removed from the publisher");
pg_log_warning_hint("Set the configuration parameter \"%s\" to -1 to ensure that required WAL files are not prematurely removed.", "max_slot_wal_keep_size");
}
/* The target server must be a standby */ if (!server_is_in_recovery(conn))
{
pg_log_error("target server must be a standby");
disconnect_database(conn, true);
}
/*------------------------------------------------------------------------ *Logicalreplicationrequiresafewparameterstobesetonsubscriber. *Sincetheseparametersarenotarequirementforphysicalreplication, *weshouldcheckittomakesureitwon'tfail. * *-max_active_replication_origins>=numberofdbstobeconverted *-max_logical_replication_workers>=numberofdbstobeconverted *-max_worker_processes>=1+numberofdbstobeconverted *------------------------------------------------------------------------
*/
res = PQexec(conn, "SELECT setting FROM pg_catalog.pg_settings WHERE name IN (" "'max_logical_replication_workers', " "'max_active_replication_origins', " "'max_worker_processes', " "'primary_slot_name') " "ORDER BY name");
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("could not obtain subscriber settings: %s",
PQresultErrorMessage(res));
disconnect_database(conn, true);
}
if (max_reporigins < num_dbs)
{
pg_log_error("subscriber requires %d active replication origins, but only %d remain",
num_dbs, max_reporigins);
pg_log_error_hint("Increase the configuration parameter \"%s\" to at least %d.", "max_active_replication_origins", num_dbs);
failed = true;
}
if (max_lrworkers < num_dbs)
{
pg_log_error("subscriber requires %d logical replication workers, but only %d remain",
num_dbs, max_lrworkers);
pg_log_error_hint("Increase the configuration parameter \"%s\" to at least %d.", "max_logical_replication_workers", num_dbs);
failed = true;
}
if (max_wprocs < num_dbs + 1)
{
pg_log_error("subscriber requires %d worker processes, but only %d remain",
num_dbs + 1, max_wprocs);
pg_log_error_hint("Increase the configuration parameter \"%s\" to at least %d.", "max_worker_processes", num_dbs + 1);
failed = true;
}
/* *Constructaquerystring.Thesecommandsareallowedtobeexecuted *withinatransaction.
*/
appendPQExpBuffer(query, "ALTER SUBSCRIPTION %s DISABLE;",
subname_esc);
appendPQExpBuffer(query, " ALTER SUBSCRIPTION %s SET (slot_name = NONE);",
subname_esc);
appendPQExpBuffer(query, " DROP SUBSCRIPTION %s;", subname_esc);
PQfreemem(subname_esc);
if (dry_run)
pg_log_info("dry-run: would drop subscription \"%s\" in database \"%s\"",
subname, dbname); else
{
pg_log_info("dropping subscription \"%s\" in database \"%s\"",
subname, dbname);
res = PQexec(conn, query->data);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
pg_log_error("could not drop subscription \"%s\": %s",
subname, PQresultErrorMessage(res));
disconnect_database(conn, true);
}
appendPQExpBuffer(query, "SELECT s.subname FROM pg_catalog.pg_subscription s " "INNER JOIN pg_catalog.pg_database d ON (s.subdbid = d.oid) " "WHERE d.datname = %s",
dbname);
res = PQexec(conn, query->data);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("could not obtain pre-existing subscriptions: %s",
PQresultErrorMessage(res));
disconnect_database(conn, true);
}
for (int i = 0; i < PQntuples(res); i++)
drop_existing_subscriptions(conn, PQgetvalue(res, i, 0),
dbinfo->dbname);
conn = connect_database(dbinfo[0].subconninfo, false); if (conn != NULL)
{ /* Get failover replication slot names */
res = PQexec(conn, "SELECT slot_name FROM pg_catalog.pg_replication_slots WHERE failover");
if (PQresultStatus(res) == PGRES_TUPLES_OK)
{ /* Remove failover replication slots from subscriber */ for (int i = 0; i < PQntuples(res); i++)
drop_replication_slot(conn, &dbinfo[0], PQgetvalue(res, i, 0));
} else
{
pg_log_warning("could not obtain failover replication slot information: %s",
PQresultErrorMessage(res));
pg_log_warning_hint("Drop the failover replication slots on subscriber soon to avoid retention of WAL files.");
}
PQclear(res);
disconnect_database(conn, false);
} else
{
pg_log_warning("could not drop failover replication slot");
pg_log_warning_hint("Drop the failover replication slots on subscriber soon to avoid retention of WAL files.");
}
}
if (dry_run)
pg_log_info("dry-run: would create the replication slot \"%s\" in database \"%s\" on publisher",
slot_name, dbinfo->dbname); else
pg_log_info("creating the replication slot \"%s\" in database \"%s\" on publisher",
slot_name, dbinfo->dbname);
if (dry_run)
pg_log_info("dry-run: would drop the replication slot \"%s\" in database \"%s\"",
slot_name, dbinfo->dbname); else
pg_log_info("dropping the replication slot \"%s\" in database \"%s\"",
slot_name, dbinfo->dbname);
if (!dry_run)
{
res = PQexec(conn, str->data); if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("could not drop replication slot \"%s\" in database \"%s\": %s",
slot_name, dbinfo->dbname, PQresultErrorMessage(res));
dbinfo->made_replslot = false; /* don't try again. */
}
PQclear(res);
}
destroyPQExpBuffer(str);
}
/* *Reportsasuitablemessageifpg_ctlfails.
*/ staticvoid
pg_ctl_status(constchar *pg_ctl_cmd, int rc)
{ if (rc != 0)
{ if (WIFEXITED(rc))
{
pg_log_error("pg_ctl failed with exit code %d", WEXITSTATUS(rc));
} elseif (WIFSIGNALED(rc))
{ #ifdefined(WIN32)
pg_log_error("pg_ctl was terminated by exception 0x%X",
WTERMSIG(rc));
pg_log_error_detail("See C include file \"ntstatus.h\" for a description of the hexadecimal value."); #else
pg_log_error("pg_ctl was terminated by signal %d: %s",
WTERMSIG(rc), pg_strsignal(WTERMSIG(rc))); #endif
} else
{
pg_log_error("pg_ctl exited with unrecognized status %d", rc);
}
/* *Returnsaftertheserverfinishestherecoveryprocess. * *Ifrecovery_timeoutoptionisset,terminateabnormallywithoutfinishing *therecoveryprocess.Bydefault,itwaitsforever. * *XXXIstherecoveryprocessstillinprogress?Whenrecoveryprocesshasa *betterprogressreportingmechanism,itshouldbeaddedhere.
*/ staticvoid
wait_for_end_recovery(constchar *conninfo, conststruct CreateSubscriberOptions *opt)
{
PGconn *conn; int status = POSTMASTER_STILL_STARTING; int timer = 0;
pg_log_info("waiting for the target server to reach the consistent state");
conn = connect_database(conninfo, true);
for (;;)
{ /* Did the recovery process finish? We're done if so. */ if (dry_run || !server_is_in_recovery(conn))
{
status = POSTMASTER_READY;
recovery_ended = true; break;
}
/* Bail out after recovery_timeout seconds if this option is set */ if (opt->recovery_timeout > 0 && timer >= opt->recovery_timeout)
{
stop_standby_server(subscriber_dir);
pg_log_error("recovery timed out");
disconnect_database(conn, true);
}
if (status == POSTMASTER_STILL_STARTING)
pg_fatal("server did not end recovery");
pg_log_info("target server reached the consistent state");
pg_log_info_hint("If pg_createsubscriber fails after this point, you must recreate the physical replica before continuing.");
}
if (dry_run)
pg_log_info("dry-run: would drop publication \"%s\" in database \"%s\"",
pubname, dbname); else
pg_log_info("dropping publication \"%s\" in database \"%s\"",
pubname, dbname);
if (drop_all_pubs)
{
pg_log_info("dropping all existing publications in database \"%s\"",
dbinfo->dbname);
/* Fetch all publication names */
res = PQexec(conn, "SELECT pubname FROM pg_catalog.pg_publication;"); if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("could not obtain publication information: %s",
PQresultErrorMessage(res));
PQclear(res);
disconnect_database(conn, true);
}
/* Drop each publication */ for (int i = 0; i < PQntuples(res); i++)
drop_publication(conn, PQgetvalue(res, i, 0), dbinfo->dbname,
&dbinfo->made_publication);
if (dry_run)
pg_log_info("dry-run: would set the replication progress (node name \"%s\", LSN %s) in database \"%s\"",
originname, lsnstr, dbinfo->dbname); else
pg_log_info("setting the replication progress (node name \"%s\", LSN %s) in database \"%s\"",
originname, lsnstr, dbinfo->dbname);
if (!dry_run)
{
res = PQexec(conn, str->data); if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("could not set replication progress for subscription \"%s\": %s",
dbinfo->subname, PQresultErrorMessage(res));
disconnect_database(conn, true);
}
PQclear(res);
}
/* If a database name was specified, just connect to it. */ if (dbnamespecified)
conn = connect_database(opt->pub_conninfo_str, true); else
{ /* Otherwise, try postgres first and then template1. */ char *conninfo;
res = PQexec(conn, "SELECT datname FROM pg_database WHERE datistemplate = false AND datallowconn AND datconnlimit <> -2 ORDER BY 1"); if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
pg_log_error("could not obtain a list of databases: %s", PQresultErrorMessage(res));
PQclear(res);
disconnect_database(conn, true);
}
for (int i = 0; i < PQntuples(res); i++)
{ constchar *dbname = PQgetvalue(res, i, 0);
/* *Don'tallowittoberunasroot.Itusespg_ctlwhichdoesnotallow *iteither.
*/ #ifndef WIN32 if (geteuid() == 0)
{
pg_log_error("cannot be executed by \"root\"");
pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
progname); exit(1);
} #endif
get_restricted_token();
while ((c = getopt_long(argc, argv, "ad:D:np:P:s:t:TU:v",
long_options, &option_index)) != -1)
{ switch (c)
{ case'a':
opt.all_dbs = true; break; case'd': if (!simple_string_list_member(&opt.database_names, optarg))
{
simple_string_list_append(&opt.database_names, optarg);
num_dbs++;
} else
pg_fatal("database \"%s\" specified more than once for -d/--database", optarg); break; case'D':
subscriber_dir = pg_strdup(optarg);
canonicalize_path(subscriber_dir); break; case'n':
dry_run = true; break; case'p':
opt.sub_port = pg_strdup(optarg); break; case'P':
opt.pub_conninfo_str = pg_strdup(optarg); break; case's':
opt.socket_dir = pg_strdup(optarg);
canonicalize_path(opt.socket_dir); break; case't':
opt.recovery_timeout = atoi(optarg); break; case'T':
opt.two_phase = true; break; case'U':
opt.sub_username = pg_strdup(optarg); break; case'v':
pg_logging_increase_verbosity(); break; case1:
opt.config_file = pg_strdup(optarg); break; case2: if (!simple_string_list_member(&opt.pub_names, optarg))
{
simple_string_list_append(&opt.pub_names, optarg);
num_pubs++;
} else
pg_fatal("publication \"%s\" specified more than once for --publication", optarg); break; case3: if (!simple_string_list_member(&opt.replslot_names, optarg))
{
simple_string_list_append(&opt.replslot_names, optarg);
num_replslots++;
} else
pg_fatal("replication slot \"%s\" specified more than once for --replication-slot", optarg); break; case4: if (!simple_string_list_member(&opt.sub_names, optarg))
{
simple_string_list_append(&opt.sub_names, optarg);
num_subs++;
} else
pg_fatal("subscription \"%s\" specified more than once for --subscription", optarg); break; case5: if (!simple_string_list_member(&opt.objecttypes_to_clean, optarg))
simple_string_list_append(&opt.objecttypes_to_clean, optarg); else
pg_fatal("object type \"%s\" specified more than once for --clean", optarg); break; default: /* getopt_long already emitted a complaint */
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
}
/* Validate that --all is not used with incompatible options */ if (opt.all_dbs)
{ char *bad_switch = NULL;
if (bad_switch)
{
pg_log_error("options %s and %s cannot be used together",
bad_switch, "-a/--all");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
}
/* Any non-option arguments? */ if (optind < argc)
{
pg_log_error("too many command-line arguments (first is \"%s\")",
argv[optind]);
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
/* Required arguments */ if (subscriber_dir == NULL)
{
pg_log_error("no subscriber data directory specified");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
/* If socket directory is not provided, use the current directory */ if (opt.socket_dir == NULL)
{ char cwd[MAXPGPATH];
if (!getcwd(cwd, MAXPGPATH))
pg_fatal("could not determine current directory");
opt.socket_dir = pg_strdup(cwd);
canonicalize_path(opt.socket_dir);
}
if (opt.database_names.head == NULL)
{
pg_log_info("no database was specified");
/* *Trytoobtainthedbnamefromthepublisherconninfo.Ifdbname *parameterisnotavailable,errorout.
*/ if (dbname_conninfo)
{
simple_string_list_append(&opt.database_names, dbname_conninfo);
num_dbs++;
pg_log_info("database name \"%s\" was extracted from the publisher connection string",
dbname_conninfo);
} else
{
pg_log_error("no database name specified");
pg_log_error_hint("Try \"%s --help\" for more information.",
progname); exit(1);
}
}
/* Number of object names must match number of databases */ if (num_pubs > 0 && num_pubs != num_dbs)
{
pg_log_error("wrong number of publication names specified");
pg_log_error_detail("The number of specified publication names (%d) must match the number of specified database names (%d).",
num_pubs, num_dbs); exit(1);
} if (num_subs > 0 && num_subs != num_dbs)
{
pg_log_error("wrong number of subscription names specified");
pg_log_error_detail("The number of specified subscription names (%d) must match the number of specified database names (%d).",
num_subs, num_dbs); exit(1);
} if (num_replslots > 0 && num_replslots != num_dbs)
{
pg_log_error("wrong number of replication slot names specified");
pg_log_error_detail("The number of specified replication slot names (%d) must match the number of specified database names (%d).",
num_replslots, num_dbs); exit(1);
}
/* Verify the object types specified for removal from the subscriber */ for (SimpleStringListCell *cell = opt.objecttypes_to_clean.head; cell; cell = cell->next)
{ if (pg_strcasecmp(cell->val, "publications") == 0)
dbinfos.objecttypes_to_clean |= OBJECTTYPE_PUBLICATIONS; else
{
pg_log_error("invalid object type \"%s\" specified for %s",
cell->val, "--clean");
pg_log_error_hint("The valid value is: \"%s\"", "publications"); exit(1);
}
}
/* Get the absolute path of pg_ctl and pg_resetwal on the subscriber */
pg_ctl_path = get_exec_path(argv[0], "pg_ctl");
pg_resetwal_path = get_exec_path(argv[0], "pg_resetwal");
/* Rudimentary check for a data directory */
check_data_directory(subscriber_dir);
/* Register a function to clean up objects in case of failure */
atexit(cleanup_objects_atexit);
/* *Checkifthesubscriberdatadirectoryhasthesamesystemidentifier *thanthepublisherdatadirectory.
*/
pub_sysid = get_primary_sysid(dbinfos.dbinfo[0].pubconninfo);
sub_sysid = get_standby_sysid(subscriber_dir); if (pub_sysid != sub_sysid)
pg_fatal("subscriber data directory is not a copy of the source database cluster");
/* *Thestandbyservermustnotberunning.Iftheserverisstartedunder *servicemanagerandpg_createsubscriberstopsit,theservicemanager *mightreacttothisactionandstarttheserveragain.Therefore, *refusetoproceediftheserverisrunningtoavoidpossiblefailures.
*/ if (stat(pidfile, &statbuf) == 0)
{
pg_log_error("standby server is running");
pg_log_error_hint("Stop the standby server and try again."); exit(1);
}
/* *Startashort-livedstandbyserverwithtemporaryparameters(provided *bycommand-lineoptions).Thegoalistoavoidconnectionsduringthe *transformationsteps.
*/
pg_log_info("starting the standby server with command-line options");
start_standby_server(&opt, true, false);
/* Check if the standby server is ready for logical replication */
check_subscriber(dbinfos.dbinfo);
/* Check if the primary server is ready for logical replication */
check_publisher(dbinfos.dbinfo);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.