diff --git a/contrib/pg_upgrade/Makefile b/contrib/pg_upgrade/Makefile index 364b20df1ba..dec57a6130d 100644 --- a/contrib/pg_upgrade/Makefile +++ b/contrib/pg_upgrade/Makefile @@ -11,7 +11,7 @@ OBJS = check.o controldata.o dump.o exec.o file.o function.o info.o \ PG_CPPFLAGS = -DFRONTEND -DDLSUFFIX=\"$(DLSUFFIX)\" -I$(srcdir) -I$(libpq_srcdir) PG_LIBS = $(libpq_pgport) -EXTRA_CLEAN = delete_old_cluster.sh log/ tmp_check/ +EXTRA_CLEAN = analyze_new_cluster.sh delete_old_cluster.sh log/ tmp_check/ ifdef USE_PGXS PG_CONFIG = pg_config diff --git a/contrib/pg_upgrade/check.c b/contrib/pg_upgrade/check.c index aa896b58237..efb080befd4 100644 --- a/contrib/pg_upgrade/check.c +++ b/contrib/pg_upgrade/check.c @@ -183,13 +183,10 @@ issue_warnings(char *sequence_script_file_name) if (sequence_script_file_name) { prep_status("Adjusting sequences"); - exec_prog(true, true, UTILITY_LOG_FILE, NULL, - SYSTEMQUOTE "\"%s/psql\" --echo-queries " - "--set ON_ERROR_STOP=on " - "--no-psqlrc --port %d --username \"%s\" " - "-f \"%s\" --dbname template1 >> \"%s\" 2>&1" SYSTEMQUOTE, - new_cluster.bindir, new_cluster.port, os_info.user, - sequence_script_file_name, UTILITY_LOG_FILE); + exec_prog(UTILITY_LOG_FILE, NULL, true, + "\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s\"", + new_cluster.bindir, cluster_conn_opts(&new_cluster), + sequence_script_file_name); unlink(sequence_script_file_name); check_ok(); } diff --git a/contrib/pg_upgrade/dump.c b/contrib/pg_upgrade/dump.c index 07a3b548a9f..b905ab084d7 100644 --- a/contrib/pg_upgrade/dump.c +++ b/contrib/pg_upgrade/dump.c @@ -23,12 +23,11 @@ generate_old_dump(void) * --binary-upgrade records the width of dropped columns in pg_class, and * restores the frozenid's for databases and relations. */ - exec_prog(true, true, UTILITY_LOG_FILE, NULL, - SYSTEMQUOTE "\"%s/pg_dumpall\" --port %d --username \"%s\" " - "--schema-only --binary-upgrade %s > \"%s\" 2>> \"%s\"" - SYSTEMQUOTE, new_cluster.bindir, old_cluster.port, os_info.user, + exec_prog(UTILITY_LOG_FILE, NULL, true, + "\"%s/pg_dumpall\" %s --schema-only --binary-upgrade %s -f %s", + new_cluster.bindir, cluster_conn_opts(&old_cluster), log_opts.verbose ? "--verbose" : "", - ALL_DUMP_FILE, UTILITY_LOG_FILE); + ALL_DUMP_FILE); check_ok(); } diff --git a/contrib/pg_upgrade/exec.c b/contrib/pg_upgrade/exec.c index 6f993df53a3..c75d9dbcc97 100644 --- a/contrib/pg_upgrade/exec.c +++ b/contrib/pg_upgrade/exec.c @@ -26,77 +26,81 @@ static int win32_check_directory_write_permissions(void); /* * exec_prog() + * Execute an external program with stdout/stderr redirected, and report + * errors * - * Formats a command from the given argument list and executes that - * command. If the command executes, exec_prog() returns 1 otherwise - * exec_prog() logs an error message and returns 0. Either way, the command - * line to be executed is saved to the specified log file. + * Formats a command from the given argument list, logs it to the log file, + * and attempts to execute that command. If the command executes + * successfully, exec_prog() returns true. * - * If throw_error is TRUE, this function will throw a PG_FATAL error - * instead of returning should an error occur. The command it appended - * to log_file; opt_log_file is used in error messages. + * If the command fails, an error message is saved to the specified log_file. + * If throw_error is true, this raises a PG_FATAL error and pg_upgrade + * terminates; otherwise it is just reported as PG_REPORT and exec_prog() + * returns false. */ -int -exec_prog(bool throw_error, bool is_priv, const char *log_file, - const char *opt_log_file, const char *fmt,...) +bool +exec_prog(const char *log_file, const char *opt_log_file, + bool throw_error, const char *fmt,...) { - va_list args; int result; - int retval; - char cmd[MAXPGPATH]; + int written; +#define MAXCMDLEN (2 * MAXPGPATH) + char cmd[MAXCMDLEN]; mode_t old_umask = 0; FILE *log; + va_list ap; - if (is_priv) - old_umask = umask(S_IRWXG | S_IRWXO); + old_umask = umask(S_IRWXG | S_IRWXO); - va_start(args, fmt); - vsnprintf(cmd, MAXPGPATH, fmt, args); - va_end(args); + written = strlcpy(cmd, SYSTEMQUOTE, strlen(SYSTEMQUOTE)); + va_start(ap, fmt); + written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap); + va_end(ap); + if (written >= MAXCMDLEN) + pg_log(PG_FATAL, "command too long\n"); + written += snprintf(cmd + written, MAXCMDLEN - written, + " >> \"%s\" 2>&1" SYSTEMQUOTE, log_file); + if (written >= MAXCMDLEN) + pg_log(PG_FATAL, "command too long\n"); if ((log = fopen_priv(log_file, "a+")) == NULL) pg_log(PG_FATAL, "cannot write to log file %s\n", log_file); pg_log(PG_VERBOSE, "%s\n", cmd); fprintf(log, "command: %s\n", cmd); + /* - * In Windows, we must close then reopen the log file so the file is - * not open while the command is running, or we get a share violation. + * In Windows, we must close the log file at this point so the file is not + * open while the command is running, or we get a share violation. */ fclose(log); result = system(cmd); - if (is_priv) - umask(old_umask); + umask(old_umask); if (result != 0) { - char opt_string[MAXPGPATH]; - - /* Create string for optional second log file */ - if (opt_log_file) - snprintf(opt_string, sizeof(opt_string), " or \"%s\"", opt_log_file); - else - opt_string[0] = '\0'; - report_status(PG_REPORT, "*failure*"); fflush(stdout); pg_log(PG_VERBOSE, "There were problems executing \"%s\"\n", cmd); - pg_log(throw_error ? PG_FATAL : PG_REPORT, - "Consult the last few lines of \"%s\"%s for\n" - "the probable cause of the failure.\n", - log_file, opt_string); - retval = 1; + if (opt_log_file) + pg_log(throw_error ? PG_FATAL : PG_REPORT, + "Consult the last few lines of \"%s\" or \"%s\" for\n" + "the probable cause of the failure.\n", + log_file, opt_log_file); + else + pg_log(throw_error ? PG_FATAL : PG_REPORT, + "Consult the last few lines of \"%s\" for\n" + "the probable cause of the failure.\n", + log_file); } - else - retval = 0; if ((log = fopen_priv(log_file, "a+")) == NULL) pg_log(PG_FATAL, "cannot write to log file %s\n", log_file); fprintf(log, "\n\n"); fclose(log); - return retval; + return result == 0; } diff --git a/contrib/pg_upgrade/file.c b/contrib/pg_upgrade/file.c index 550967009b3..a5d92c62fce 100644 --- a/contrib/pg_upgrade/file.c +++ b/contrib/pg_upgrade/file.c @@ -103,10 +103,10 @@ copyAndUpdateFile(pageCnvCtx *pageConverter, /* * linkAndUpdateFile() * - * Creates a symbolic link between the given relation files. We use + * Creates a hard link between the given relation files. We use * this function to perform a true in-place update. If the on-disk * format of the new cluster is bit-for-bit compatible with the on-disk - * format of the old cluster, we can simply symlink each relation + * format of the old cluster, we can simply link each relation * instead of copying the data from the old cluster to the new cluster. */ const char * diff --git a/contrib/pg_upgrade/option.c b/contrib/pg_upgrade/option.c index 94bce505cb6..6d5a93a0a56 100644 --- a/contrib/pg_upgrade/option.c +++ b/contrib/pg_upgrade/option.c @@ -9,6 +9,8 @@ #include "postgres.h" +#include "miscadmin.h" + #include "pg_upgrade.h" #include @@ -376,3 +378,64 @@ adjust_data_dir(ClusterInfo *cluster) check_ok(); } + + +/* + * get_sock_dir + * + * Identify the socket directory to use for this cluster. If we're doing + * a live check (old cluster only), we need to find out where the postmaster + * is listening. Otherwise, we're going to put the socket into the current + * directory. + */ +void +get_sock_dir(ClusterInfo *cluster, bool live_check) +{ +#ifdef HAVE_UNIX_SOCKETS + if (!live_check) + { + /* Use the current directory for the socket */ + cluster->sockdir = pg_malloc(MAXPGPATH); + if (!getcwd(cluster->sockdir, MAXPGPATH)) + pg_log(PG_FATAL, "cannot find current directory\n"); + } + else + { + /* + * If we are doing a live check, we will use the old cluster's Unix + * domain socket directory so we can connect to the live server. + */ + + /* sockdir was added to postmaster.pid in PG 9.1 */ + if (GET_MAJOR_VERSION(cluster->major_version) >= 901) + { + char filename[MAXPGPATH]; + FILE *fp; + int i; + + snprintf(filename, sizeof(filename), "%s/postmaster.pid", + cluster->pgdata); + if ((fp = fopen(filename, "r")) == NULL) + pg_log(PG_FATAL, "Could not get socket directory of the old server\n"); + + cluster->sockdir = pg_malloc(MAXPGPATH); + for (i = 0; i < LOCK_FILE_LINE_SOCKET_DIR; i++) + if (fgets(cluster->sockdir, MAXPGPATH, fp) == NULL) + pg_log(PG_FATAL, "Could not get socket directory of the old server\n"); + + fclose(fp); + + /* Remove trailing newline */ + if (strchr(cluster->sockdir, '\n') != NULL) + *strchr(cluster->sockdir, '\n') = '\0'; + } + else + { + /* Can't get live sockdir, so assume the default is OK. */ + cluster->sockdir = NULL; + } + } +#else /* !HAVE_UNIX_SOCKETS */ + cluster->sockdir = NULL; +#endif +} diff --git a/contrib/pg_upgrade/pg_upgrade.c b/contrib/pg_upgrade/pg_upgrade.c index 5a7e8e4c6e1..54c886e11ca 100644 --- a/contrib/pg_upgrade/pg_upgrade.c +++ b/contrib/pg_upgrade/pg_upgrade.c @@ -88,6 +88,9 @@ main(int argc, char **argv) check_cluster_versions(); check_cluster_compatibility(live_check); + get_sock_dir(&old_cluster, live_check); + get_sock_dir(&new_cluster, false); + check_old_cluster(live_check, &sequence_script_file_name); @@ -140,11 +143,10 @@ main(int argc, char **argv) * because there is no need to have the schema load use new oids. */ prep_status("Setting next OID for new cluster"); - exec_prog(true, true, UTILITY_LOG_FILE, NULL, - SYSTEMQUOTE "\"%s/pg_resetxlog\" -o %u \"%s\" >> \"%s\" 2>&1" - SYSTEMQUOTE, + exec_prog(UTILITY_LOG_FILE, NULL, true, + "\"%s/pg_resetxlog\" -o %u \"%s\"", new_cluster.bindir, old_cluster.controldata.chkpnt_nxtoid, - new_cluster.pgdata, UTILITY_LOG_FILE); + new_cluster.pgdata); check_ok(); create_script_for_cluster_analyze(&analyze_script_file_name); @@ -211,11 +213,10 @@ prepare_new_cluster(void) * --analyze so autovacuum doesn't update statistics later */ prep_status("Analyzing all rows in the new cluster"); - exec_prog(true, true, UTILITY_LOG_FILE, NULL, - SYSTEMQUOTE "\"%s/vacuumdb\" --port %d --username \"%s\" " - "--all --analyze %s >> \"%s\" 2>&1" SYSTEMQUOTE, - new_cluster.bindir, new_cluster.port, os_info.user, - log_opts.verbose ? "--verbose" : "", UTILITY_LOG_FILE); + exec_prog(UTILITY_LOG_FILE, NULL, true, + "\"%s/vacuumdb\" %s --all --analyze %s", + new_cluster.bindir, cluster_conn_opts(&new_cluster), + log_opts.verbose ? "--verbose" : ""); check_ok(); /* @@ -225,11 +226,10 @@ prepare_new_cluster(void) * later. */ prep_status("Freezing all rows on the new cluster"); - exec_prog(true, true, UTILITY_LOG_FILE, NULL, - SYSTEMQUOTE "\"%s/vacuumdb\" --port %d --username \"%s\" " - "--all --freeze %s >> \"%s\" 2>&1" SYSTEMQUOTE, - new_cluster.bindir, new_cluster.port, os_info.user, - log_opts.verbose ? "--verbose" : "", UTILITY_LOG_FILE); + exec_prog(UTILITY_LOG_FILE, NULL, true, + "\"%s/vacuumdb\" %s --all --freeze %s", + new_cluster.bindir, cluster_conn_opts(&new_cluster), + log_opts.verbose ? "--verbose" : ""); check_ok(); get_pg_database_relfilenode(&new_cluster); @@ -263,14 +263,10 @@ prepare_new_databases(void) * support functions in template1 but pg_dumpall creates database using * the template0 template. */ - exec_prog(true, true, RESTORE_LOG_FILE, NULL, - SYSTEMQUOTE "\"%s/psql\" --echo-queries " - "--set ON_ERROR_STOP=on " - /* --no-psqlrc prevents AUTOCOMMIT=off */ - "--no-psqlrc --port %d --username \"%s\" " - "-f \"%s\" --dbname template1 >> \"%s\" 2>&1" SYSTEMQUOTE, - new_cluster.bindir, new_cluster.port, os_info.user, - GLOBALS_DUMP_FILE, RESTORE_LOG_FILE); + exec_prog(RESTORE_LOG_FILE, NULL, true, + "\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s\"", + new_cluster.bindir, cluster_conn_opts(&new_cluster), + GLOBALS_DUMP_FILE); check_ok(); /* we load this to get a current list of databases */ @@ -296,13 +292,10 @@ create_new_objects(void) check_ok(); prep_status("Restoring database schema to new cluster"); - exec_prog(true, true, RESTORE_LOG_FILE, NULL, - SYSTEMQUOTE "\"%s/psql\" --echo-queries " - "--set ON_ERROR_STOP=on " - "--no-psqlrc --port %d --username \"%s\" " - "-f \"%s\" --dbname template1 >> \"%s\" 2>&1" SYSTEMQUOTE, - new_cluster.bindir, new_cluster.port, os_info.user, - DB_DUMP_FILE, RESTORE_LOG_FILE); + exec_prog(RESTORE_LOG_FILE, NULL, true, + "\"%s/psql\" " EXEC_PSQL_ARGS " %s -f \"%s\"", + new_cluster.bindir, cluster_conn_opts(&new_cluster), + DB_DUMP_FILE); check_ok(); /* regenerate now that we have objects in the databases */ @@ -311,55 +304,60 @@ create_new_objects(void) uninstall_support_functions_from_new_cluster(); } +/* + * Delete the given subdirectory contents from the new cluster, and copy the + * files from the old cluster into it. + */ +static void +copy_subdir_files(char *subdir) +{ + char old_path[MAXPGPATH]; + char new_path[MAXPGPATH]; + + prep_status("Deleting files from new %s", subdir); + + snprintf(old_path, sizeof(old_path), "%s/%s", old_cluster.pgdata, subdir); + snprintf(new_path, sizeof(new_path), "%s/%s", new_cluster.pgdata, subdir); + if (!rmtree(new_path, true)) + pg_log(PG_FATAL, "could not delete directory \"%s\"\n", new_path); + check_ok(); + + prep_status("Copying old %s to new server", subdir); + + exec_prog(UTILITY_LOG_FILE, NULL, true, +#ifndef WIN32 + "cp -Rf \"%s\" \"%s\"", +#else + /* flags: everything, no confirm, quiet, overwrite read-only */ + "xcopy /e /y /q /r \"%s\" \"%s\\\"", +#endif + old_path, new_path); + + check_ok(); +} static void copy_clog_xlog_xid(void) { - char old_clog_path[MAXPGPATH]; - char new_clog_path[MAXPGPATH]; - /* copy old commit logs to new data dir */ - prep_status("Deleting new commit clogs"); - - snprintf(old_clog_path, sizeof(old_clog_path), "%s/pg_clog", old_cluster.pgdata); - snprintf(new_clog_path, sizeof(new_clog_path), "%s/pg_clog", new_cluster.pgdata); - if (!rmtree(new_clog_path, true)) - pg_log(PG_FATAL, "could not delete directory \"%s\"\n", new_clog_path); - check_ok(); - - prep_status("Copying old commit clogs to new server"); - exec_prog(true, false, UTILITY_LOG_FILE, NULL, -#ifndef WIN32 - SYSTEMQUOTE "%s \"%s\" \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE, - "cp -Rf", -#else - /* flags: everything, no confirm, quiet, overwrite read-only */ - SYSTEMQUOTE "%s \"%s\" \"%s\\\" >> \"%s\" 2>&1" SYSTEMQUOTE, - "xcopy /e /y /q /r", -#endif - old_clog_path, new_clog_path, UTILITY_LOG_FILE); - check_ok(); + copy_subdir_files("pg_clog"); /* set the next transaction id of the new cluster */ prep_status("Setting next transaction ID for new cluster"); - exec_prog(true, true, UTILITY_LOG_FILE, NULL, - SYSTEMQUOTE - "\"%s/pg_resetxlog\" -f -x %u \"%s\" >> \"%s\" 2>&1" - SYSTEMQUOTE, new_cluster.bindir, - old_cluster.controldata.chkpnt_nxtxid, - new_cluster.pgdata, UTILITY_LOG_FILE); + exec_prog(UTILITY_LOG_FILE, NULL, true, + "\"%s/pg_resetxlog\" -f -x %u \"%s\"", + new_cluster.bindir, old_cluster.controldata.chkpnt_nxtxid, + new_cluster.pgdata); check_ok(); /* now reset the wal archives in the new cluster */ prep_status("Resetting WAL archives"); - exec_prog(true, true, UTILITY_LOG_FILE, NULL, - SYSTEMQUOTE - "\"%s/pg_resetxlog\" -l %u,%u,%u \"%s\" >> \"%s\" 2>&1" - SYSTEMQUOTE, new_cluster.bindir, + exec_prog(UTILITY_LOG_FILE, NULL, true, + "\"%s/pg_resetxlog\" -l %u,%u,%u \"%s\"", new_cluster.bindir, old_cluster.controldata.chkpnt_tli, old_cluster.controldata.logid, old_cluster.controldata.nxtlogseg, - new_cluster.pgdata, UTILITY_LOG_FILE); + new_cluster.pgdata); check_ok(); } diff --git a/contrib/pg_upgrade/pg_upgrade.h b/contrib/pg_upgrade/pg_upgrade.h index 77c7150b318..36f3adaf7b9 100644 --- a/contrib/pg_upgrade/pg_upgrade.h +++ b/contrib/pg_upgrade/pg_upgrade.h @@ -227,6 +227,7 @@ typedef struct char *bindir; /* pathname for cluster's executable directory */ char *pgopts; /* options to pass to the server, like pg_ctl * -o */ + char *sockdir; /* directory for Unix Domain socket, if any */ unsigned short port; /* port number where postmaster is waiting */ uint32 major_version; /* PG_VERSION of cluster */ char major_version_str[64]; /* string PG_VERSION of cluster */ @@ -317,10 +318,11 @@ void split_old_dump(void); /* exec.c */ -int -exec_prog(bool throw_error, bool is_priv, const char *log_file, - const char *opt_log_file, const char *cmd,...) -__attribute__((format(PG_PRINTF_ATTRIBUTE, 5, 6))); +#define EXEC_PSQL_ARGS "--echo-queries --set ON_ERROR_STOP=on --no-psqlrc --dbname=template1" +bool +exec_prog(const char *log_file, const char *opt_log_file, + bool throw_error, const char *fmt,...) +__attribute__((format(PG_PRINTF_ATTRIBUTE, 4, 5))); void verify_directories(void); bool is_server_running(const char *datadir); @@ -387,6 +389,7 @@ void print_maps(FileNameMap *maps, int n, void parseCommandLine(int argc, char *argv[]); void adjust_data_dir(ClusterInfo *cluster); +void get_sock_dir(ClusterInfo *cluster, bool live_check); /* relfilenode.c */ @@ -407,6 +410,8 @@ PGresult * executeQueryOrDie(PGconn *conn, const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3))); +char *cluster_conn_opts(ClusterInfo *cluster); + void start_postmaster(ClusterInfo *cluster); void stop_postmaster(bool fast); uint32 get_major_server_version(ClusterInfo *cluster); diff --git a/contrib/pg_upgrade/server.c b/contrib/pg_upgrade/server.c index e94a897c92c..11e7e75d78f 100644 --- a/contrib/pg_upgrade/server.c +++ b/contrib/pg_upgrade/server.c @@ -46,21 +46,54 @@ connectToServer(ClusterInfo *cluster, const char *db_name) /* * get_db_conn() * - * get database connection + * get database connection, using named database + standard params for cluster */ static PGconn * get_db_conn(ClusterInfo *cluster, const char *db_name) { - char conn_opts[MAXPGPATH]; + char conn_opts[2 * NAMEDATALEN + MAXPGPATH + 100]; - snprintf(conn_opts, sizeof(conn_opts), - "dbname = '%s' user = '%s' port = %d", db_name, os_info.user, - cluster->port); + if (cluster->sockdir) + snprintf(conn_opts, sizeof(conn_opts), + "dbname = '%s' user = '%s' host = '%s' port = %d", + db_name, os_info.user, cluster->sockdir, cluster->port); + else + snprintf(conn_opts, sizeof(conn_opts), + "dbname = '%s' user = '%s' port = %d", + db_name, os_info.user, cluster->port); return PQconnectdb(conn_opts); } +/* + * cluster_conn_opts() + * + * Return standard command-line options for connecting to this cluster when + * using psql, pg_dump, etc. Ideally this would match what get_db_conn() + * sets, but the utilities we need aren't very consistent about the treatment + * of database name options, so we leave that out. + * + * Note result is in static storage, so use it right away. + */ +char * +cluster_conn_opts(ClusterInfo *cluster) +{ + static char conn_opts[MAXPGPATH + NAMEDATALEN + 100]; + + if (cluster->sockdir) + snprintf(conn_opts, sizeof(conn_opts), + "--host \"%s\" --port %d --username \"%s\"", + cluster->sockdir, cluster->port, os_info.user); + else + snprintf(conn_opts, sizeof(conn_opts), + "--port %d --username \"%s\"", + cluster->port, os_info.user); + + return conn_opts; +} + + /* * executeQueryOrDie() * @@ -140,10 +173,11 @@ stop_postmaster_atexit(void) void start_postmaster(ClusterInfo *cluster) { - char cmd[MAXPGPATH]; + char cmd[MAXPGPATH * 4 + 1000]; PGconn *conn; bool exit_hook_registered = false; - int pg_ctl_return = 0; + bool pg_ctl_return = false; + char socket_string[MAXPGPATH + 200]; if (!exit_hook_registered) { @@ -151,6 +185,23 @@ start_postmaster(ClusterInfo *cluster) exit_hook_registered = true; } + socket_string[0] = '\0'; + +#ifdef HAVE_UNIX_SOCKETS + /* prevent TCP/IP connections, restrict socket access */ + strcat(socket_string, + " -c listen_addresses='' -c unix_socket_permissions=0700"); + + /* Have a sockdir? Tell the postmaster. */ + if (cluster->sockdir) + snprintf(socket_string + strlen(socket_string), + sizeof(socket_string) - strlen(socket_string), + " -c %s='%s'", + (GET_MAJOR_VERSION(cluster->major_version) < 903) ? + "unix_socket_directory" : "unix_socket_directories", + cluster->sockdir); +#endif + /* * Using autovacuum=off disables cleanup vacuum and analyze, but freeze * vacuums can still happen, so we set autovacuum_freeze_max_age to its @@ -159,22 +210,23 @@ start_postmaster(ClusterInfo *cluster) * not touch them. */ snprintf(cmd, sizeof(cmd), - SYSTEMQUOTE "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" " - "-o \"-p %d %s %s\" start >> \"%s\" 2>&1" SYSTEMQUOTE, + "\"%s/pg_ctl\" -w -l \"%s\" -D \"%s\" -o \"-p %d %s %s%s\" start", cluster->bindir, SERVER_LOG_FILE, cluster->pgconfig, cluster->port, (cluster->controldata.cat_ver >= BINARY_UPGRADE_SERVER_FLAG_CAT_VER) ? "-b" : "-c autovacuum=off -c autovacuum_freeze_max_age=2000000000", - cluster->pgopts ? cluster->pgopts : "", SERVER_START_LOG_FILE); + cluster->pgopts ? cluster->pgopts : "", socket_string); /* * Don't throw an error right away, let connecting throw the error because * it might supply a reason for the failure. */ - pg_ctl_return = exec_prog(false, true, SERVER_START_LOG_FILE, - /* pass both file names if the differ */ - (strcmp(SERVER_LOG_FILE, SERVER_START_LOG_FILE) != 0) ? + pg_ctl_return = exec_prog(SERVER_START_LOG_FILE, + /* pass both file names if they differ */ + (strcmp(SERVER_LOG_FILE, + SERVER_START_LOG_FILE) != 0) ? SERVER_LOG_FILE : NULL, + false, "%s", cmd); /* Check to see if we can connect to the server; if not, report it. */ @@ -185,13 +237,14 @@ start_postmaster(ClusterInfo *cluster) PQerrorMessage(conn)); if (conn) PQfinish(conn); - pg_log(PG_FATAL, "could not connect to %s postmaster started with the command: %s\n", + pg_log(PG_FATAL, "could not connect to %s postmaster started with the command:\n" + "%s\n", CLUSTER_NAME(cluster), cmd); } PQfinish(conn); /* If the connection didn't fail, fail now */ - if (pg_ctl_return != 0) + if (!pg_ctl_return) pg_log(PG_FATAL, "pg_ctl failed to start the %s server, or connection failed\n", CLUSTER_NAME(cluster)); @@ -202,7 +255,6 @@ start_postmaster(ClusterInfo *cluster) void stop_postmaster(bool fast) { - char cmd[MAXPGPATH]; ClusterInfo *cluster; if (os_info.running_cluster == &old_cluster) @@ -212,14 +264,11 @@ stop_postmaster(bool fast) else return; /* no cluster running */ - snprintf(cmd, sizeof(cmd), - SYSTEMQUOTE "\"%s/pg_ctl\" -w -D \"%s\" -o \"%s\" " - "%s stop >> \"%s\" 2>&1" SYSTEMQUOTE, - cluster->bindir, cluster->pgconfig, - cluster->pgopts ? cluster->pgopts : "", - fast ? "-m fast" : "", SERVER_STOP_LOG_FILE); - - exec_prog(fast ? false : true, true, SERVER_STOP_LOG_FILE, NULL, "%s", cmd); + exec_prog(SERVER_STOP_LOG_FILE, NULL, !fast, + "\"%s/pg_ctl\" -w -D \"%s\" -o \"%s\" %s stop", + cluster->bindir, cluster->pgconfig, + cluster->pgopts ? cluster->pgopts : "", + fast ? "-m fast" : ""); os_info.running_cluster = NULL; } diff --git a/contrib/pg_upgrade/test.sh b/contrib/pg_upgrade/test.sh index 299b7a5c477..31e30af7774 100644 --- a/contrib/pg_upgrade/test.sh +++ b/contrib/pg_upgrade/test.sh @@ -107,6 +107,7 @@ initdb pg_upgrade -d "${PGDATA}.old" -D "${PGDATA}" -b "$oldbindir" -B "$bindir" pg_ctl start -l "$logdir/postmaster2.log" -w +sh ./analyze_new_cluster.sh pg_dumpall >"$temp_root"/dump2.sql || pg_dumpall2_status=$? pg_ctl -m fast stop if [ -n "$pg_dumpall2_status" ]; then @@ -114,6 +115,8 @@ if [ -n "$pg_dumpall2_status" ]; then exit 1 fi +sh ./delete_old_cluster.sh + if diff -q "$temp_root"/dump1.sql "$temp_root"/dump2.sql; then echo PASSED exit 0 diff --git a/doc/src/sgml/pgupgrade.sgml b/doc/src/sgml/pgupgrade.sgml index fcbe551e764..9e43f3ce133 100644 --- a/doc/src/sgml/pgupgrade.sgml +++ b/doc/src/sgml/pgupgrade.sgml @@ -367,8 +367,10 @@ pg_upgrade.exe Obviously, no one should be accessing the clusters during the upgrade. pg_upgrade defaults to running servers on port 50432 to avoid unintended client connections. - You can use the same port numbers for both clusters because the - old and new clusters will not be running at the same time. + You can use the same port number for both clusters when doing an + upgrade because the old and new clusters will not be running at the + same time. However, when checking an old running server, the old + and new port numbers must be different. @@ -517,6 +519,14 @@ psql --username postgres --file script.sql postgres -d /real-data-directory -o '-D /configuration-directory'. + + If doing + A Log-Shipping Standby Server () cannot be upgraded because the server must allow writes. The simplest way