summaryrefslogtreecommitdiffstats
path: root/src/bin/pg_rewind
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:17:33 +0000
commit5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch)
tree739caf8c461053357daa9f162bef34516c7bf452 /src/bin/pg_rewind
parentInitial commit. (diff)
downloadpostgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz
postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/bin/pg_rewind')
-rw-r--r--src/bin/pg_rewind/.gitignore6
-rw-r--r--src/bin/pg_rewind/Makefile60
-rw-r--r--src/bin/pg_rewind/datapagemap.c127
-rw-r--r--src/bin/pg_rewind/datapagemap.h29
-rw-r--r--src/bin/pg_rewind/file_ops.c477
-rw-r--r--src/bin/pg_rewind/file_ops.h29
-rw-r--r--src/bin/pg_rewind/filemap.c831
-rw-r--r--src/bin/pg_rewind/filemap.h113
-rw-r--r--src/bin/pg_rewind/libpq_source.c675
-rw-r--r--src/bin/pg_rewind/local_source.c187
-rw-r--r--src/bin/pg_rewind/nls.mk7
-rw-r--r--src/bin/pg_rewind/parsexlog.c462
-rw-r--r--src/bin/pg_rewind/pg_rewind.c1169
-rw-r--r--src/bin/pg_rewind/pg_rewind.h56
-rw-r--r--src/bin/pg_rewind/po/de.po1010
-rw-r--r--src/bin/pg_rewind/po/el.po1016
-rw-r--r--src/bin/pg_rewind/po/es.po1013
-rw-r--r--src/bin/pg_rewind/po/fr.po1300
-rw-r--r--src/bin/pg_rewind/po/it.po1190
-rw-r--r--src/bin/pg_rewind/po/ja.po1009
-rw-r--r--src/bin/pg_rewind/po/ka.po1101
-rw-r--r--src/bin/pg_rewind/po/ko.po1073
-rw-r--r--src/bin/pg_rewind/po/ru.po1208
-rw-r--r--src/bin/pg_rewind/po/sv.po1010
-rw-r--r--src/bin/pg_rewind/po/uk.po993
-rw-r--r--src/bin/pg_rewind/po/zh_CN.po959
-rw-r--r--src/bin/pg_rewind/rewind_source.h86
-rw-r--r--src/bin/pg_rewind/t/001_basic.pl194
-rw-r--r--src/bin/pg_rewind/t/002_databases.pl77
-rw-r--r--src/bin/pg_rewind/t/003_extrafiles.pl106
-rw-r--r--src/bin/pg_rewind/t/004_pg_xlog_symlink.pl80
-rw-r--r--src/bin/pg_rewind/t/005_same_timeline.pl24
-rw-r--r--src/bin/pg_rewind/t/006_options.pl45
-rw-r--r--src/bin/pg_rewind/t/007_standby_source.pl179
-rw-r--r--src/bin/pg_rewind/t/008_min_recovery_point.pl177
-rw-r--r--src/bin/pg_rewind/t/009_growing_files.pl77
-rw-r--r--src/bin/pg_rewind/t/RewindTest.pm393
-rw-r--r--src/bin/pg_rewind/timeline.c130
38 files changed, 18678 insertions, 0 deletions
diff --git a/src/bin/pg_rewind/.gitignore b/src/bin/pg_rewind/.gitignore
new file mode 100644
index 0000000..79ddca3
--- /dev/null
+++ b/src/bin/pg_rewind/.gitignore
@@ -0,0 +1,6 @@
+# Files generated during build
+/xlogreader.c
+/pg_rewind
+
+# Generated by test suite
+/tmp_check/
diff --git a/src/bin/pg_rewind/Makefile b/src/bin/pg_rewind/Makefile
new file mode 100644
index 0000000..e8a4713
--- /dev/null
+++ b/src/bin/pg_rewind/Makefile
@@ -0,0 +1,60 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/bin/pg_rewind
+#
+# Portions Copyright (c) 2013-2022, PostgreSQL Global Development Group
+#
+# src/bin/pg_rewind/Makefile
+#
+#-------------------------------------------------------------------------
+
+PGFILEDESC = "pg_rewind - synchronize a data directory with another one forked from"
+PGAPPICON = win32
+
+subdir = src/bin/pg_rewind
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+override CPPFLAGS := -I$(libpq_srcdir) -DFRONTEND $(CPPFLAGS)
+LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
+
+OBJS = \
+ $(WIN32RES) \
+ datapagemap.o \
+ file_ops.o \
+ filemap.o \
+ libpq_source.o \
+ local_source.o \
+ parsexlog.o \
+ pg_rewind.o \
+ timeline.o \
+ xlogreader.o
+
+EXTRA_CLEAN = xlogreader.c
+
+all: pg_rewind
+
+pg_rewind: $(OBJS) | submake-libpq submake-libpgport
+ $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+
+xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/%
+ rm -f $@ && $(LN_S) $< .
+
+install: all installdirs
+ $(INSTALL_PROGRAM) pg_rewind$(X) '$(DESTDIR)$(bindir)/pg_rewind$(X)'
+
+installdirs:
+ $(MKDIR_P) '$(DESTDIR)$(bindir)'
+
+uninstall:
+ rm -f '$(DESTDIR)$(bindir)/pg_rewind$(X)'
+
+clean distclean maintainer-clean:
+ rm -f pg_rewind$(X) $(OBJS) xlogreader.c
+ rm -rf tmp_check
+
+check:
+ $(prove_check)
+
+installcheck:
+ $(prove_installcheck)
diff --git a/src/bin/pg_rewind/datapagemap.c b/src/bin/pg_rewind/datapagemap.c
new file mode 100644
index 0000000..cbc3bc5
--- /dev/null
+++ b/src/bin/pg_rewind/datapagemap.c
@@ -0,0 +1,127 @@
+/*-------------------------------------------------------------------------
+ *
+ * datapagemap.c
+ * A data structure for keeping track of data pages that have changed.
+ *
+ * This is a fairly simple bitmap.
+ *
+ * Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include "common/logging.h"
+#include "datapagemap.h"
+
+struct datapagemap_iterator
+{
+ datapagemap_t *map;
+ BlockNumber nextblkno;
+};
+
+/*****
+ * Public functions
+ */
+
+/*
+ * Add a block to the bitmap.
+ */
+void
+datapagemap_add(datapagemap_t *map, BlockNumber blkno)
+{
+ int offset;
+ int bitno;
+
+ offset = blkno / 8;
+ bitno = blkno % 8;
+
+ /* enlarge or create bitmap if needed */
+ if (map->bitmapsize <= offset)
+ {
+ int oldsize = map->bitmapsize;
+ int newsize;
+
+ /*
+ * The minimum to hold the new bit is offset + 1. But add some
+ * headroom, so that we don't need to repeatedly enlarge the bitmap in
+ * the common case that blocks are modified in order, from beginning
+ * of a relation to the end.
+ */
+ newsize = offset + 1;
+ newsize += 10;
+
+ map->bitmap = pg_realloc(map->bitmap, newsize);
+
+ /* zero out the newly allocated region */
+ memset(&map->bitmap[oldsize], 0, newsize - oldsize);
+
+ map->bitmapsize = newsize;
+ }
+
+ /* Set the bit */
+ map->bitmap[offset] |= (1 << bitno);
+}
+
+/*
+ * Start iterating through all entries in the page map.
+ *
+ * After datapagemap_iterate, call datapagemap_next to return the entries,
+ * until it returns false. After you're done, use pg_free() to destroy the
+ * iterator.
+ */
+datapagemap_iterator_t *
+datapagemap_iterate(datapagemap_t *map)
+{
+ datapagemap_iterator_t *iter;
+
+ iter = pg_malloc(sizeof(datapagemap_iterator_t));
+ iter->map = map;
+ iter->nextblkno = 0;
+
+ return iter;
+}
+
+bool
+datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno)
+{
+ datapagemap_t *map = iter->map;
+
+ for (;;)
+ {
+ BlockNumber blk = iter->nextblkno;
+ int nextoff = blk / 8;
+ int bitno = blk % 8;
+
+ if (nextoff >= map->bitmapsize)
+ break;
+
+ iter->nextblkno++;
+
+ if (map->bitmap[nextoff] & (1 << bitno))
+ {
+ *blkno = blk;
+ return true;
+ }
+ }
+
+ /* no more set bits in this bitmap. */
+ return false;
+}
+
+/*
+ * A debugging aid. Prints out the contents of the page map.
+ */
+void
+datapagemap_print(datapagemap_t *map)
+{
+ datapagemap_iterator_t *iter;
+ BlockNumber blocknum;
+
+ iter = datapagemap_iterate(map);
+ while (datapagemap_next(iter, &blocknum))
+ pg_log_debug("block %u", blocknum);
+
+ pg_free(iter);
+}
diff --git a/src/bin/pg_rewind/datapagemap.h b/src/bin/pg_rewind/datapagemap.h
new file mode 100644
index 0000000..ae4965f
--- /dev/null
+++ b/src/bin/pg_rewind/datapagemap.h
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ *
+ * datapagemap.h
+ *
+ * Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef DATAPAGEMAP_H
+#define DATAPAGEMAP_H
+
+#include "storage/block.h"
+#include "storage/relfilenode.h"
+
+struct datapagemap
+{
+ char *bitmap;
+ int bitmapsize;
+};
+
+typedef struct datapagemap datapagemap_t;
+typedef struct datapagemap_iterator datapagemap_iterator_t;
+
+extern void datapagemap_add(datapagemap_t *map, BlockNumber blkno);
+extern datapagemap_iterator_t *datapagemap_iterate(datapagemap_t *map);
+extern bool datapagemap_next(datapagemap_iterator_t *iter, BlockNumber *blkno);
+extern void datapagemap_print(datapagemap_t *map);
+
+#endif /* DATAPAGEMAP_H */
diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c
new file mode 100644
index 0000000..6cb288f
--- /dev/null
+++ b/src/bin/pg_rewind/file_ops.c
@@ -0,0 +1,477 @@
+/*-------------------------------------------------------------------------
+ *
+ * file_ops.c
+ * Helper functions for operating on files.
+ *
+ * Most of the functions in this file are helper functions for writing to
+ * the target data directory. The functions check the --dry-run flag, and
+ * do nothing if it's enabled. You should avoid accessing the target files
+ * directly but if you do, make sure you honor the --dry-run mode!
+ *
+ * Portions Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "common/file_perm.h"
+#include "common/file_utils.h"
+#include "file_ops.h"
+#include "filemap.h"
+#include "pg_rewind.h"
+
+/*
+ * Currently open target file.
+ */
+static int dstfd = -1;
+static char dstpath[MAXPGPATH] = "";
+
+static void create_target_dir(const char *path);
+static void remove_target_dir(const char *path);
+static void create_target_symlink(const char *path, const char *link);
+static void remove_target_symlink(const char *path);
+
+static void recurse_dir(const char *datadir, const char *parentpath,
+ process_file_callback_t callback);
+
+/*
+ * Open a target file for writing. If 'trunc' is true and the file already
+ * exists, it will be truncated.
+ */
+void
+open_target_file(const char *path, bool trunc)
+{
+ int mode;
+
+ if (dry_run)
+ return;
+
+ if (dstfd != -1 && !trunc &&
+ strcmp(path, &dstpath[strlen(datadir_target) + 1]) == 0)
+ return; /* already open */
+
+ close_target_file();
+
+ snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
+
+ mode = O_WRONLY | O_CREAT | PG_BINARY;
+ if (trunc)
+ mode |= O_TRUNC;
+ dstfd = open(dstpath, mode, pg_file_create_mode);
+ if (dstfd < 0)
+ pg_fatal("could not open target file \"%s\": %m",
+ dstpath);
+}
+
+/*
+ * Close target file, if it's open.
+ */
+void
+close_target_file(void)
+{
+ if (dstfd == -1)
+ return;
+
+ if (close(dstfd) != 0)
+ pg_fatal("could not close target file \"%s\": %m",
+ dstpath);
+
+ dstfd = -1;
+}
+
+void
+write_target_range(char *buf, off_t begin, size_t size)
+{
+ size_t writeleft;
+ char *p;
+
+ /* update progress report */
+ fetch_done += size;
+ progress_report(false);
+
+ if (dry_run)
+ return;
+
+ if (lseek(dstfd, begin, SEEK_SET) == -1)
+ pg_fatal("could not seek in target file \"%s\": %m",
+ dstpath);
+
+ writeleft = size;
+ p = buf;
+ while (writeleft > 0)
+ {
+ ssize_t writelen;
+
+ errno = 0;
+ writelen = write(dstfd, p, writeleft);
+ if (writelen < 0)
+ {
+ /* if write didn't set errno, assume problem is no disk space */
+ if (errno == 0)
+ errno = ENOSPC;
+ pg_fatal("could not write file \"%s\": %m",
+ dstpath);
+ }
+
+ p += writelen;
+ writeleft -= writelen;
+ }
+
+ /* keep the file open, in case we need to copy more blocks in it */
+}
+
+
+void
+remove_target(file_entry_t *entry)
+{
+ Assert(entry->action == FILE_ACTION_REMOVE);
+ Assert(entry->target_exists);
+
+ switch (entry->target_type)
+ {
+ case FILE_TYPE_DIRECTORY:
+ remove_target_dir(entry->path);
+ break;
+
+ case FILE_TYPE_REGULAR:
+ remove_target_file(entry->path, false);
+ break;
+
+ case FILE_TYPE_SYMLINK:
+ remove_target_symlink(entry->path);
+ break;
+
+ case FILE_TYPE_UNDEFINED:
+ pg_fatal("undefined file type for \"%s\"", entry->path);
+ break;
+ }
+}
+
+void
+create_target(file_entry_t *entry)
+{
+ Assert(entry->action == FILE_ACTION_CREATE);
+ Assert(!entry->target_exists);
+
+ switch (entry->source_type)
+ {
+ case FILE_TYPE_DIRECTORY:
+ create_target_dir(entry->path);
+ break;
+
+ case FILE_TYPE_SYMLINK:
+ create_target_symlink(entry->path, entry->source_link_target);
+ break;
+
+ case FILE_TYPE_REGULAR:
+ /* can't happen. Regular files are created with open_target_file. */
+ pg_fatal("invalid action (CREATE) for regular file");
+ break;
+
+ case FILE_TYPE_UNDEFINED:
+ pg_fatal("undefined file type for \"%s\"", entry->path);
+ break;
+ }
+}
+
+/*
+ * Remove a file from target data directory. If missing_ok is true, it
+ * is fine for the target file to not exist.
+ */
+void
+remove_target_file(const char *path, bool missing_ok)
+{
+ char dstpath[MAXPGPATH];
+
+ if (dry_run)
+ return;
+
+ snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
+ if (unlink(dstpath) != 0)
+ {
+ if (errno == ENOENT && missing_ok)
+ return;
+
+ pg_fatal("could not remove file \"%s\": %m",
+ dstpath);
+ }
+}
+
+void
+truncate_target_file(const char *path, off_t newsize)
+{
+ char dstpath[MAXPGPATH];
+ int fd;
+
+ if (dry_run)
+ return;
+
+ snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
+
+ fd = open(dstpath, O_WRONLY, pg_file_create_mode);
+ if (fd < 0)
+ pg_fatal("could not open file \"%s\" for truncation: %m",
+ dstpath);
+
+ if (ftruncate(fd, newsize) != 0)
+ pg_fatal("could not truncate file \"%s\" to %u: %m",
+ dstpath, (unsigned int) newsize);
+
+ close(fd);
+}
+
+static void
+create_target_dir(const char *path)
+{
+ char dstpath[MAXPGPATH];
+
+ if (dry_run)
+ return;
+
+ snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
+ if (mkdir(dstpath, pg_dir_create_mode) != 0)
+ pg_fatal("could not create directory \"%s\": %m",
+ dstpath);
+}
+
+static void
+remove_target_dir(const char *path)
+{
+ char dstpath[MAXPGPATH];
+
+ if (dry_run)
+ return;
+
+ snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
+ if (rmdir(dstpath) != 0)
+ pg_fatal("could not remove directory \"%s\": %m",
+ dstpath);
+}
+
+static void
+create_target_symlink(const char *path, const char *link)
+{
+ char dstpath[MAXPGPATH];
+
+ if (dry_run)
+ return;
+
+ snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
+ if (symlink(link, dstpath) != 0)
+ pg_fatal("could not create symbolic link at \"%s\": %m",
+ dstpath);
+}
+
+static void
+remove_target_symlink(const char *path)
+{
+ char dstpath[MAXPGPATH];
+
+ if (dry_run)
+ return;
+
+ snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path);
+ if (unlink(dstpath) != 0)
+ pg_fatal("could not remove symbolic link \"%s\": %m",
+ dstpath);
+}
+
+/*
+ * Sync target data directory to ensure that modifications are safely on disk.
+ *
+ * We do this once, for the whole data directory, for performance reasons. At
+ * the end of pg_rewind's run, the kernel is likely to already have flushed
+ * most dirty buffers to disk. Additionally fsync_pgdata uses a two-pass
+ * approach (only initiating writeback in the first pass), which often reduces
+ * the overall amount of IO noticeably.
+ */
+void
+sync_target_dir(void)
+{
+ if (!do_sync || dry_run)
+ return;
+
+ fsync_pgdata(datadir_target, PG_VERSION_NUM);
+}
+
+
+/*
+ * Read a file into memory. The file to be read is <datadir>/<path>.
+ * The file contents are returned in a malloc'd buffer, and *filesize
+ * is set to the length of the file.
+ *
+ * The returned buffer is always zero-terminated; the size of the returned
+ * buffer is actually *filesize + 1. That's handy when reading a text file.
+ * This function can be used to read binary files as well, you can just
+ * ignore the zero-terminator in that case.
+ */
+char *
+slurpFile(const char *datadir, const char *path, size_t *filesize)
+{
+ int fd;
+ char *buffer;
+ struct stat statbuf;
+ char fullpath[MAXPGPATH];
+ int len;
+ int r;
+
+ snprintf(fullpath, sizeof(fullpath), "%s/%s", datadir, path);
+
+ if ((fd = open(fullpath, O_RDONLY | PG_BINARY, 0)) == -1)
+ pg_fatal("could not open file \"%s\" for reading: %m",
+ fullpath);
+
+ if (fstat(fd, &statbuf) < 0)
+ pg_fatal("could not open file \"%s\" for reading: %m",
+ fullpath);
+
+ len = statbuf.st_size;
+
+ buffer = pg_malloc(len + 1);
+
+ r = read(fd, buffer, len);
+ if (r != len)
+ {
+ if (r < 0)
+ pg_fatal("could not read file \"%s\": %m",
+ fullpath);
+ else
+ pg_fatal("could not read file \"%s\": read %d of %zu",
+ fullpath, r, (Size) len);
+ }
+ close(fd);
+
+ /* Zero-terminate the buffer. */
+ buffer[len] = '\0';
+
+ if (filesize)
+ *filesize = len;
+ return buffer;
+}
+
+/*
+ * Traverse through all files in a data directory, calling 'callback'
+ * for each file.
+ */
+void
+traverse_datadir(const char *datadir, process_file_callback_t callback)
+{
+ recurse_dir(datadir, NULL, callback);
+}
+
+/*
+ * recursive part of traverse_datadir
+ *
+ * parentpath is the current subdirectory's path relative to datadir,
+ * or NULL at the top level.
+ */
+static void
+recurse_dir(const char *datadir, const char *parentpath,
+ process_file_callback_t callback)
+{
+ DIR *xldir;
+ struct dirent *xlde;
+ char fullparentpath[MAXPGPATH];
+
+ if (parentpath)
+ snprintf(fullparentpath, MAXPGPATH, "%s/%s", datadir, parentpath);
+ else
+ snprintf(fullparentpath, MAXPGPATH, "%s", datadir);
+
+ xldir = opendir(fullparentpath);
+ if (xldir == NULL)
+ pg_fatal("could not open directory \"%s\": %m",
+ fullparentpath);
+
+ while (errno = 0, (xlde = readdir(xldir)) != NULL)
+ {
+ struct stat fst;
+ char fullpath[MAXPGPATH * 2];
+ char path[MAXPGPATH * 2];
+
+ if (strcmp(xlde->d_name, ".") == 0 ||
+ strcmp(xlde->d_name, "..") == 0)
+ continue;
+
+ snprintf(fullpath, sizeof(fullpath), "%s/%s", fullparentpath, xlde->d_name);
+
+ if (lstat(fullpath, &fst) < 0)
+ {
+ if (errno == ENOENT)
+ {
+ /*
+ * File doesn't exist anymore. This is ok, if the new primary
+ * is running and the file was just removed. If it was a data
+ * file, there should be a WAL record of the removal. If it
+ * was something else, it couldn't have been anyway.
+ *
+ * TODO: But complain if we're processing the target dir!
+ */
+ }
+ else
+ pg_fatal("could not stat file \"%s\": %m",
+ fullpath);
+ }
+
+ if (parentpath)
+ snprintf(path, sizeof(path), "%s/%s", parentpath, xlde->d_name);
+ else
+ snprintf(path, sizeof(path), "%s", xlde->d_name);
+
+ if (S_ISREG(fst.st_mode))
+ callback(path, FILE_TYPE_REGULAR, fst.st_size, NULL);
+ else if (S_ISDIR(fst.st_mode))
+ {
+ callback(path, FILE_TYPE_DIRECTORY, 0, NULL);
+ /* recurse to handle subdirectories */
+ recurse_dir(datadir, path, callback);
+ }
+#ifndef WIN32
+ else if (S_ISLNK(fst.st_mode))
+#else
+ else if (pgwin32_is_junction(fullpath))
+#endif
+ {
+#if defined(HAVE_READLINK) || defined(WIN32)
+ char link_target[MAXPGPATH];
+ int len;
+
+ len = readlink(fullpath, link_target, sizeof(link_target));
+ if (len < 0)
+ pg_fatal("could not read symbolic link \"%s\": %m",
+ fullpath);
+ if (len >= sizeof(link_target))
+ pg_fatal("symbolic link \"%s\" target is too long",
+ fullpath);
+ link_target[len] = '\0';
+
+ callback(path, FILE_TYPE_SYMLINK, 0, link_target);
+
+ /*
+ * If it's a symlink within pg_tblspc, we need to recurse into it,
+ * to process all the tablespaces. We also follow a symlink if
+ * it's for pg_wal. Symlinks elsewhere are ignored.
+ */
+ if ((parentpath && strcmp(parentpath, "pg_tblspc") == 0) ||
+ strcmp(path, "pg_wal") == 0)
+ recurse_dir(datadir, path, callback);
+#else
+ pg_fatal("\"%s\" is a symbolic link, but symbolic links are not supported on this platform",
+ fullpath);
+#endif /* HAVE_READLINK */
+ }
+ }
+
+ if (errno)
+ pg_fatal("could not read directory \"%s\": %m",
+ fullparentpath);
+
+ if (closedir(xldir))
+ pg_fatal("could not close directory \"%s\": %m",
+ fullparentpath);
+}
diff --git a/src/bin/pg_rewind/file_ops.h b/src/bin/pg_rewind/file_ops.h
new file mode 100644
index 0000000..54a853b
--- /dev/null
+++ b/src/bin/pg_rewind/file_ops.h
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ *
+ * file_ops.h
+ * Helper functions for operating on files
+ *
+ * Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FILE_OPS_H
+#define FILE_OPS_H
+
+#include "filemap.h"
+
+extern void open_target_file(const char *path, bool trunc);
+extern void write_target_range(char *buf, off_t begin, size_t size);
+extern void close_target_file(void);
+extern void remove_target_file(const char *path, bool missing_ok);
+extern void truncate_target_file(const char *path, off_t newsize);
+extern void create_target(file_entry_t *t);
+extern void remove_target(file_entry_t *t);
+extern void sync_target_dir(void);
+
+extern char *slurpFile(const char *datadir, const char *path, size_t *filesize);
+
+typedef void (*process_file_callback_t) (const char *path, file_type_t type, size_t size, const char *link_target);
+extern void traverse_datadir(const char *datadir, process_file_callback_t callback);
+
+#endif /* FILE_OPS_H */
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
new file mode 100644
index 0000000..6252931
--- /dev/null
+++ b/src/bin/pg_rewind/filemap.c
@@ -0,0 +1,831 @@
+/*-------------------------------------------------------------------------
+ *
+ * filemap.c
+ * A data structure for keeping track of files that have changed.
+ *
+ * This source file contains the logic to decide what to do with different
+ * kinds of files, and the data structure to support it. Before modifying
+ * anything, pg_rewind collects information about all the files and their
+ * attributes in the target and source data directories. It also scans the
+ * WAL log in the target, and collects information about data blocks that
+ * were changed. All this information is stored in a hash table, using the
+ * file path relative to the root of the data directory as the key.
+ *
+ * After collecting all the information required, the decide_file_actions()
+ * function scans the hash table and decides what action needs to be taken
+ * for each file. Finally, it sorts the array to the final order that the
+ * actions should be executed in.
+ *
+ * Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "catalog/pg_tablespace_d.h"
+#include "common/hashfn.h"
+#include "common/string.h"
+#include "datapagemap.h"
+#include "filemap.h"
+#include "pg_rewind.h"
+#include "storage/fd.h"
+
+/*
+ * Define a hash table which we can use to store information about the files
+ * appearing in source and target systems.
+ */
+static uint32 hash_string_pointer(const char *s);
+#define SH_PREFIX filehash
+#define SH_ELEMENT_TYPE file_entry_t
+#define SH_KEY_TYPE const char *
+#define SH_KEY path
+#define SH_HASH_KEY(tb, key) hash_string_pointer(key)
+#define SH_EQUAL(tb, a, b) (strcmp(a, b) == 0)
+#define SH_SCOPE static inline
+#define SH_RAW_ALLOCATOR pg_malloc0
+#define SH_DECLARE
+#define SH_DEFINE
+#include "lib/simplehash.h"
+
+#define FILEHASH_INITIAL_SIZE 1000
+
+static filehash_hash *filehash;
+
+static bool isRelDataFile(const char *path);
+static char *datasegpath(RelFileNode rnode, ForkNumber forknum,
+ BlockNumber segno);
+
+static file_entry_t *insert_filehash_entry(const char *path);
+static file_entry_t *lookup_filehash_entry(const char *path);
+static int final_filemap_cmp(const void *a, const void *b);
+static bool check_file_excluded(const char *path, bool is_source);
+
+/*
+ * Definition of one element part of an exclusion list, used to exclude
+ * contents when rewinding. "name" is the name of the file or path to
+ * check for exclusion. If "match_prefix" is true, any items matching
+ * the name as prefix are excluded.
+ */
+struct exclude_list_item
+{
+ const char *name;
+ bool match_prefix;
+};
+
+/*
+ * The contents of these directories are removed or recreated during server
+ * start so they are not included in data processed by pg_rewind.
+ *
+ * Note: those lists should be kept in sync with what basebackup.c provides.
+ * Some of the values, contrary to what basebackup.c uses, are hardcoded as
+ * they are defined in backend-only headers. So this list is maintained
+ * with a best effort in mind.
+ */
+static const char *excludeDirContents[] =
+{
+ /*
+ * Skip temporary statistics files. PG_STAT_TMP_DIR must be skipped
+ * because extensions like pg_stat_statements store data there.
+ */
+ "pg_stat_tmp", /* defined as PG_STAT_TMP_DIR */
+
+ /*
+ * It is generally not useful to backup the contents of this directory
+ * even if the intention is to restore to another primary. See backup.sgml
+ * for a more detailed description.
+ */
+ "pg_replslot",
+
+ /* Contents removed on startup, see dsm_cleanup_for_mmap(). */
+ "pg_dynshmem", /* defined as PG_DYNSHMEM_DIR */
+
+ /* Contents removed on startup, see AsyncShmemInit(). */
+ "pg_notify",
+
+ /*
+ * Old contents are loaded for possible debugging but are not required for
+ * normal operation, see SerialInit().
+ */
+ "pg_serial",
+
+ /* Contents removed on startup, see DeleteAllExportedSnapshotFiles(). */
+ "pg_snapshots",
+
+ /* Contents zeroed on startup, see StartupSUBTRANS(). */
+ "pg_subtrans",
+
+ /* end of list */
+ NULL
+};
+
+/*
+ * List of files excluded from filemap processing. Files are excluded
+ * if their prefix match.
+ */
+static const struct exclude_list_item excludeFiles[] =
+{
+ /* Skip auto conf temporary file. */
+ {"postgresql.auto.conf.tmp", false}, /* defined as PG_AUTOCONF_FILENAME */
+
+ /* Skip current log file temporary file */
+ {"current_logfiles.tmp", false}, /* defined as
+ * LOG_METAINFO_DATAFILE_TMP */
+
+ /* Skip relation cache because it is rebuilt on startup */
+ {"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
+
+ /*
+ * If there is a backup_label or tablespace_map file, it indicates that a
+ * recovery failed and this cluster probably can't be rewound, but exclude
+ * them anyway if they are found.
+ */
+ {"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
+ {"tablespace_map", false}, /* defined as TABLESPACE_MAP */
+
+ /*
+ * If there's a backup_manifest, it belongs to a backup that was used to
+ * start this server. It is *not* correct for this backup. Our
+ * backup_manifest is injected into the backup separately if users want
+ * it.
+ */
+ {"backup_manifest", false},
+
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
+ /* end of list */
+ {NULL, false}
+};
+
+/*
+ * Initialize the hash table for the file map.
+ */
+void
+filehash_init(void)
+{
+ filehash = filehash_create(FILEHASH_INITIAL_SIZE, NULL);
+}
+
+/* Look up entry for 'path', creating a new one if it doesn't exist */
+static file_entry_t *
+insert_filehash_entry(const char *path)
+{
+ file_entry_t *entry;
+ bool found;
+
+ entry = filehash_insert(filehash, path, &found);
+ if (!found)
+ {
+ entry->path = pg_strdup(path);
+ entry->isrelfile = isRelDataFile(path);
+
+ entry->target_exists = false;
+ entry->target_type = FILE_TYPE_UNDEFINED;
+ entry->target_size = 0;
+ entry->target_link_target = NULL;
+ entry->target_pages_to_overwrite.bitmap = NULL;
+ entry->target_pages_to_overwrite.bitmapsize = 0;
+
+ entry->source_exists = false;
+ entry->source_type = FILE_TYPE_UNDEFINED;
+ entry->source_size = 0;
+ entry->source_link_target = NULL;
+
+ entry->action = FILE_ACTION_UNDECIDED;
+ }
+
+ return entry;
+}
+
+static file_entry_t *
+lookup_filehash_entry(const char *path)
+{
+ return filehash_lookup(filehash, path);
+}
+
+/*
+ * Callback for processing source file list.
+ *
+ * This is called once for every file in the source server. We record the
+ * type and size of the file, so that decide_file_action() can later decide what
+ * to do with it.
+ */
+void
+process_source_file(const char *path, file_type_t type, size_t size,
+ const char *link_target)
+{
+ file_entry_t *entry;
+
+ /*
+ * Pretend that pg_wal is a directory, even if it's really a symlink. We
+ * don't want to mess with the symlink itself, nor complain if it's a
+ * symlink in source but not in target or vice versa.
+ */
+ if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK)
+ type = FILE_TYPE_DIRECTORY;
+
+ /*
+ * sanity check: a filename that looks like a data file better be a
+ * regular file
+ */
+ if (type != FILE_TYPE_REGULAR && isRelDataFile(path))
+ pg_fatal("data file \"%s\" in source is not a regular file", path);
+
+ /* Remember this source file */
+ entry = insert_filehash_entry(path);
+ if (entry->source_exists)
+ pg_fatal("duplicate source file \"%s\"", path);
+ entry->source_exists = true;
+ entry->source_type = type;
+ entry->source_size = size;
+ entry->source_link_target = link_target ? pg_strdup(link_target) : NULL;
+}
+
+/*
+ * Callback for processing target file list.
+ *
+ * Record the type and size of the file, like process_source_file() does.
+ */
+void
+process_target_file(const char *path, file_type_t type, size_t size,
+ const char *link_target)
+{
+ file_entry_t *entry;
+
+ /*
+ * Do not apply any exclusion filters here. This has advantage to remove
+ * from the target data folder all paths which have been filtered out from
+ * the source data folder when processing the source files.
+ */
+
+ /*
+ * Like in process_source_file, pretend that pg_wal is always a directory.
+ */
+ if (strcmp(path, "pg_wal") == 0 && type == FILE_TYPE_SYMLINK)
+ type = FILE_TYPE_DIRECTORY;
+
+ /* Remember this target file */
+ entry = insert_filehash_entry(path);
+ if (entry->target_exists)
+ pg_fatal("duplicate source file \"%s\"", path);
+ entry->target_exists = true;
+ entry->target_type = type;
+ entry->target_size = size;
+ entry->target_link_target = link_target ? pg_strdup(link_target) : NULL;
+}
+
+/*
+ * This callback gets called while we read the WAL in the target, for every
+ * block that has changed in the target system. It decides if the given
+ * 'blkno' in the target relfile needs to be overwritten from the source, and
+ * if so, records it in 'target_pages_to_overwrite' bitmap.
+ *
+ * NOTE: All the files on both systems must have already been added to the
+ * hash table!
+ */
+void
+process_target_wal_block_change(ForkNumber forknum, RelFileNode rnode,
+ BlockNumber blkno)
+{
+ char *path;
+ file_entry_t *entry;
+ BlockNumber blkno_inseg;
+ int segno;
+
+ segno = blkno / RELSEG_SIZE;
+ blkno_inseg = blkno % RELSEG_SIZE;
+
+ path = datasegpath(rnode, forknum, segno);
+ entry = lookup_filehash_entry(path);
+ pfree(path);
+
+ /*
+ * If the block still exists in both systems, remember it. Otherwise we
+ * can safely ignore it.
+ *
+ * If the block is beyond the EOF in the source system, or the file
+ * doesn't exist in the source at all, we're going to truncate/remove it
+ * away from the target anyway. Likewise, if it doesn't exist in the
+ * target anymore, we will copy it over with the "tail" from the source
+ * system, anyway.
+ *
+ * It is possible to find WAL for a file that doesn't exist on either
+ * system anymore. It means that the relation was dropped later in the
+ * target system, and independently on the source system too, or that it
+ * was created and dropped in the target system and it never existed in
+ * the source. Either way, we can safely ignore it.
+ */
+ if (entry)
+ {
+ Assert(entry->isrelfile);
+
+ if (entry->target_exists)
+ {
+ if (entry->target_type != FILE_TYPE_REGULAR)
+ pg_fatal("unexpected page modification for non-regular file \"%s\"",
+ entry->path);
+
+ if (entry->source_exists)
+ {
+ off_t end_offset;
+
+ end_offset = (blkno_inseg + 1) * BLCKSZ;
+ if (end_offset <= entry->source_size && end_offset <= entry->target_size)
+ datapagemap_add(&entry->target_pages_to_overwrite, blkno_inseg);
+ }
+ }
+ }
+}
+
+/*
+ * Is this the path of file that pg_rewind can skip copying?
+ */
+static bool
+check_file_excluded(const char *path, bool is_source)
+{
+ char localpath[MAXPGPATH];
+ int excludeIdx;
+ const char *filename;
+
+ /*
+ * Skip all temporary files, .../pgsql_tmp/... and .../pgsql_tmp.*
+ */
+ if (strstr(path, "/" PG_TEMP_FILE_PREFIX) != NULL ||
+ strstr(path, "/" PG_TEMP_FILES_DIR "/") != NULL)
+ {
+ return true;
+ }
+
+ /* check individual files... */
+ for (excludeIdx = 0; excludeFiles[excludeIdx].name != NULL; excludeIdx++)
+ {
+ int cmplen = strlen(excludeFiles[excludeIdx].name);
+
+ filename = last_dir_separator(path);
+ if (filename == NULL)
+ filename = path;
+ else
+ filename++;
+
+ if (!excludeFiles[excludeIdx].match_prefix)
+ cmplen++;
+ if (strncmp(filename, excludeFiles[excludeIdx].name, cmplen) == 0)
+ {
+ if (is_source)
+ pg_log_debug("entry \"%s\" excluded from source file list",
+ path);
+ else
+ pg_log_debug("entry \"%s\" excluded from target file list",
+ path);
+ return true;
+ }
+ }
+
+ /*
+ * ... And check some directories. Note that this includes any contents
+ * within the directories themselves.
+ */
+ for (excludeIdx = 0; excludeDirContents[excludeIdx] != NULL; excludeIdx++)
+ {
+ snprintf(localpath, sizeof(localpath), "%s/",
+ excludeDirContents[excludeIdx]);
+ if (strstr(path, localpath) == path)
+ {
+ if (is_source)
+ pg_log_debug("entry \"%s\" excluded from source file list",
+ path);
+ else
+ pg_log_debug("entry \"%s\" excluded from target file list",
+ path);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static const char *
+action_to_str(file_action_t action)
+{
+ switch (action)
+ {
+ case FILE_ACTION_NONE:
+ return "NONE";
+ case FILE_ACTION_COPY:
+ return "COPY";
+ case FILE_ACTION_TRUNCATE:
+ return "TRUNCATE";
+ case FILE_ACTION_COPY_TAIL:
+ return "COPY_TAIL";
+ case FILE_ACTION_CREATE:
+ return "CREATE";
+ case FILE_ACTION_REMOVE:
+ return "REMOVE";
+
+ default:
+ return "unknown";
+ }
+}
+
+/*
+ * Calculate the totals needed for progress reports.
+ */
+void
+calculate_totals(filemap_t *filemap)
+{
+ file_entry_t *entry;
+ int i;
+
+ filemap->total_size = 0;
+ filemap->fetch_size = 0;
+
+ for (i = 0; i < filemap->nentries; i++)
+ {
+ entry = filemap->entries[i];
+
+ if (entry->source_type != FILE_TYPE_REGULAR)
+ continue;
+
+ filemap->total_size += entry->source_size;
+
+ if (entry->action == FILE_ACTION_COPY)
+ {
+ filemap->fetch_size += entry->source_size;
+ continue;
+ }
+
+ if (entry->action == FILE_ACTION_COPY_TAIL)
+ filemap->fetch_size += (entry->source_size - entry->target_size);
+
+ if (entry->target_pages_to_overwrite.bitmapsize > 0)
+ {
+ datapagemap_iterator_t *iter;
+ BlockNumber blk;
+
+ iter = datapagemap_iterate(&entry->target_pages_to_overwrite);
+ while (datapagemap_next(iter, &blk))
+ filemap->fetch_size += BLCKSZ;
+
+ pg_free(iter);
+ }
+ }
+}
+
+void
+print_filemap(filemap_t *filemap)
+{
+ file_entry_t *entry;
+ int i;
+
+ for (i = 0; i < filemap->nentries; i++)
+ {
+ entry = filemap->entries[i];
+ if (entry->action != FILE_ACTION_NONE ||
+ entry->target_pages_to_overwrite.bitmapsize > 0)
+ {
+ pg_log_debug("%s (%s)", entry->path,
+ action_to_str(entry->action));
+
+ if (entry->target_pages_to_overwrite.bitmapsize > 0)
+ datapagemap_print(&entry->target_pages_to_overwrite);
+ }
+ }
+ fflush(stdout);
+}
+
+/*
+ * Does it look like a relation data file?
+ *
+ * For our purposes, only files belonging to the main fork are considered
+ * relation files. Other forks are always copied in toto, because we cannot
+ * reliably track changes to them, because WAL only contains block references
+ * for the main fork.
+ */
+static bool
+isRelDataFile(const char *path)
+{
+ RelFileNode rnode;
+ unsigned int segNo;
+ int nmatch;
+ bool matched;
+
+ /*----
+ * Relation data files can be in one of the following directories:
+ *
+ * global/
+ * shared relations
+ *
+ * base/<db oid>/
+ * regular relations, default tablespace
+ *
+ * pg_tblspc/<tblspc oid>/<tblspc version>/
+ * within a non-default tablespace (the name of the directory
+ * depends on version)
+ *
+ * And the relation data files themselves have a filename like:
+ *
+ * <oid>.<segment number>
+ *
+ *----
+ */
+ rnode.spcNode = InvalidOid;
+ rnode.dbNode = InvalidOid;
+ rnode.relNode = InvalidOid;
+ segNo = 0;
+ matched = false;
+
+ nmatch = sscanf(path, "global/%u.%u", &rnode.relNode, &segNo);
+ if (nmatch == 1 || nmatch == 2)
+ {
+ rnode.spcNode = GLOBALTABLESPACE_OID;
+ rnode.dbNode = 0;
+ matched = true;
+ }
+ else
+ {
+ nmatch = sscanf(path, "base/%u/%u.%u",
+ &rnode.dbNode, &rnode.relNode, &segNo);
+ if (nmatch == 2 || nmatch == 3)
+ {
+ rnode.spcNode = DEFAULTTABLESPACE_OID;
+ matched = true;
+ }
+ else
+ {
+ nmatch = sscanf(path, "pg_tblspc/%u/" TABLESPACE_VERSION_DIRECTORY "/%u/%u.%u",
+ &rnode.spcNode, &rnode.dbNode, &rnode.relNode,
+ &segNo);
+ if (nmatch == 3 || nmatch == 4)
+ matched = true;
+ }
+ }
+
+ /*
+ * The sscanf tests above can match files that have extra characters at
+ * the end. To eliminate such cases, cross-check that GetRelationPath
+ * creates the exact same filename, when passed the RelFileNode
+ * information we extracted from the filename.
+ */
+ if (matched)
+ {
+ char *check_path = datasegpath(rnode, MAIN_FORKNUM, segNo);
+
+ if (strcmp(check_path, path) != 0)
+ matched = false;
+
+ pfree(check_path);
+ }
+
+ return matched;
+}
+
+/*
+ * A helper function to create the path of a relation file and segment.
+ *
+ * The returned path is palloc'd
+ */
+static char *
+datasegpath(RelFileNode rnode, ForkNumber forknum, BlockNumber segno)
+{
+ char *path;
+ char *segpath;
+
+ path = relpathperm(rnode, forknum);
+ if (segno > 0)
+ {
+ segpath = psprintf("%s.%u", path, segno);
+ pfree(path);
+ return segpath;
+ }
+ else
+ return path;
+}
+
+/*
+ * In the final stage, the filemap is sorted so that removals come last.
+ * From disk space usage point of view, it would be better to do removals
+ * first, but for now, safety first. If a whole directory is deleted, all
+ * files and subdirectories inside it need to removed first. On creation,
+ * parent directory needs to be created before files and directories inside
+ * it. To achieve that, the file_action_t enum is ordered so that we can
+ * just sort on that first. Furthermore, sort REMOVE entries in reverse
+ * path order, so that "foo/bar" subdirectory is removed before "foo".
+ */
+static int
+final_filemap_cmp(const void *a, const void *b)
+{
+ file_entry_t *fa = *((file_entry_t **) a);
+ file_entry_t *fb = *((file_entry_t **) b);
+
+ if (fa->action > fb->action)
+ return 1;
+ if (fa->action < fb->action)
+ return -1;
+
+ if (fa->action == FILE_ACTION_REMOVE)
+ return strcmp(fb->path, fa->path);
+ else
+ return strcmp(fa->path, fb->path);
+}
+
+/*
+ * Decide what action to perform to a file.
+ */
+static file_action_t
+decide_file_action(file_entry_t *entry)
+{
+ const char *path = entry->path;
+
+ /*
+ * Don't touch the control file. It is handled specially, after copying
+ * all the other files.
+ */
+ if (strcmp(path, "global/pg_control") == 0)
+ return FILE_ACTION_NONE;
+
+ /*
+ * Remove all files matching the exclusion filters in the target.
+ */
+ if (check_file_excluded(path, true))
+ {
+ if (entry->target_exists)
+ return FILE_ACTION_REMOVE;
+ else
+ return FILE_ACTION_NONE;
+ }
+
+ /*
+ * Handle cases where the file is missing from one of the systems.
+ */
+ if (!entry->target_exists && entry->source_exists)
+ {
+ /*
+ * File exists in source, but not in target. Copy it in toto. (If it's
+ * a relation data file, WAL replay after rewinding should re-create
+ * it anyway. But there's no harm in copying it now.)
+ */
+ switch (entry->source_type)
+ {
+ case FILE_TYPE_DIRECTORY:
+ case FILE_TYPE_SYMLINK:
+ return FILE_ACTION_CREATE;
+ case FILE_TYPE_REGULAR:
+ return FILE_ACTION_COPY;
+ case FILE_TYPE_UNDEFINED:
+ pg_fatal("unknown file type for \"%s\"", entry->path);
+ break;
+ }
+ }
+ else if (entry->target_exists && !entry->source_exists)
+ {
+ /* File exists in target, but not source. Remove it. */
+ return FILE_ACTION_REMOVE;
+ }
+ else if (!entry->target_exists && !entry->source_exists)
+ {
+ /*
+ * Doesn't exist in either server. Why does it have an entry in the
+ * first place??
+ */
+ Assert(false);
+ return FILE_ACTION_NONE;
+ }
+
+ /*
+ * Otherwise, the file exists on both systems
+ */
+ Assert(entry->target_exists && entry->source_exists);
+
+ if (entry->source_type != entry->target_type)
+ {
+ /* But it's a different kind of object. Strange.. */
+ pg_fatal("file \"%s\" is of different type in source and target", entry->path);
+ }
+
+ /*
+ * PG_VERSION files should be identical on both systems, but avoid
+ * overwriting them for paranoia.
+ */
+ if (pg_str_endswith(entry->path, "PG_VERSION"))
+ return FILE_ACTION_NONE;
+
+ switch (entry->source_type)
+ {
+ case FILE_TYPE_DIRECTORY:
+ return FILE_ACTION_NONE;
+
+ case FILE_TYPE_SYMLINK:
+
+ /*
+ * XXX: Should we check if it points to the same target?
+ */
+ return FILE_ACTION_NONE;
+
+ case FILE_TYPE_REGULAR:
+ if (!entry->isrelfile)
+ {
+ /*
+ * It's a non-data file that we have no special processing
+ * for. Copy it in toto.
+ */
+ return FILE_ACTION_COPY;
+ }
+ else
+ {
+ /*
+ * It's a data file that exists in both systems.
+ *
+ * If it's larger in target, we can truncate it. There will
+ * also be a WAL record of the truncation in the source
+ * system, so WAL replay would eventually truncate the target
+ * too, but we might as well do it now.
+ *
+ * If it's smaller in the target, it means that it has been
+ * truncated in the target, or enlarged in the source, or
+ * both. If it was truncated in the target, we need to copy
+ * the missing tail from the source system. If it was enlarged
+ * in the source system, there will be WAL records in the
+ * source system for the new blocks, so we wouldn't need to
+ * copy them here. But we don't know which scenario we're
+ * dealing with, and there's no harm in copying the missing
+ * blocks now, so do it now.
+ *
+ * If it's the same size, do nothing here. Any blocks modified
+ * in the target will be copied based on parsing the target
+ * system's WAL, and any blocks modified in the source will be
+ * updated after rewinding, when the source system's WAL is
+ * replayed.
+ */
+ if (entry->target_size < entry->source_size)
+ return FILE_ACTION_COPY_TAIL;
+ else if (entry->target_size > entry->source_size)
+ return FILE_ACTION_TRUNCATE;
+ else
+ return FILE_ACTION_NONE;
+ }
+ break;
+
+ case FILE_TYPE_UNDEFINED:
+ pg_fatal("unknown file type for \"%s\"", path);
+ break;
+ }
+
+ /* unreachable */
+ pg_fatal("could not decide what to do with file \"%s\"", path);
+}
+
+/*
+ * Decide what to do with each file.
+ *
+ * Returns a 'filemap' with the entries in the order that their actions
+ * should be executed.
+ */
+filemap_t *
+decide_file_actions(void)
+{
+ int i;
+ filehash_iterator it;
+ file_entry_t *entry;
+ filemap_t *filemap;
+
+ filehash_start_iterate(filehash, &it);
+ while ((entry = filehash_iterate(filehash, &it)) != NULL)
+ {
+ entry->action = decide_file_action(entry);
+ }
+
+ /*
+ * Turn the hash table into an array, and sort in the order that the
+ * actions should be performed.
+ */
+ filemap = pg_malloc(offsetof(filemap_t, entries) +
+ filehash->members * sizeof(file_entry_t *));
+ filemap->nentries = filehash->members;
+ filehash_start_iterate(filehash, &it);
+ i = 0;
+ while ((entry = filehash_iterate(filehash, &it)) != NULL)
+ {
+ filemap->entries[i++] = entry;
+ }
+
+ qsort(&filemap->entries, filemap->nentries, sizeof(file_entry_t *),
+ final_filemap_cmp);
+
+ return filemap;
+}
+
+
+/*
+ * Helper function for filemap hash table.
+ */
+static uint32
+hash_string_pointer(const char *s)
+{
+ unsigned char *ss = (unsigned char *) s;
+
+ return hash_bytes(ss, strlen(s));
+}
diff --git a/src/bin/pg_rewind/filemap.h b/src/bin/pg_rewind/filemap.h
new file mode 100644
index 0000000..096f57a
--- /dev/null
+++ b/src/bin/pg_rewind/filemap.h
@@ -0,0 +1,113 @@
+/*-------------------------------------------------------------------------
+ *
+ * filemap.h
+ *
+ * Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *-------------------------------------------------------------------------
+ */
+#ifndef FILEMAP_H
+#define FILEMAP_H
+
+#include "datapagemap.h"
+#include "storage/block.h"
+#include "storage/relfilenode.h"
+
+/* these enum values are sorted in the order we want actions to be processed */
+typedef enum
+{
+ FILE_ACTION_UNDECIDED = 0, /* not decided yet */
+
+ FILE_ACTION_CREATE, /* create local directory or symbolic link */
+ FILE_ACTION_COPY, /* copy whole file, overwriting if exists */
+ FILE_ACTION_COPY_TAIL, /* copy tail from 'source_size' to
+ * 'target_size' */
+ FILE_ACTION_NONE, /* no action (we might still copy modified
+ * blocks based on the parsed WAL) */
+ FILE_ACTION_TRUNCATE, /* truncate local file to 'newsize' bytes */
+ FILE_ACTION_REMOVE /* remove local file / directory / symlink */
+} file_action_t;
+
+typedef enum
+{
+ FILE_TYPE_UNDEFINED = 0,
+
+ FILE_TYPE_REGULAR,
+ FILE_TYPE_DIRECTORY,
+ FILE_TYPE_SYMLINK
+} file_type_t;
+
+/*
+ * For every file found in the local or remote system, we have a file entry
+ * that contains information about the file on both systems. For relation
+ * files, there is also a page map that marks pages in the file that were
+ * changed in the target after the last common checkpoint.
+ *
+ * When gathering information, these are kept in a hash table, private to
+ * filemap.c. decide_file_actions() fills in the 'action' field, sorts all
+ * the entries, and returns them in an array, ready for executing the actions.
+ */
+typedef struct file_entry_t
+{
+ uint32 status; /* hash status */
+
+ const char *path;
+ bool isrelfile; /* is it a relation data file? */
+
+ /*
+ * Status of the file in the target.
+ */
+ bool target_exists;
+ file_type_t target_type;
+ size_t target_size; /* for a regular file */
+ char *target_link_target; /* for a symlink */
+
+ /*
+ * Pages that were modified in the target and need to be replaced from the
+ * source.
+ */
+ datapagemap_t target_pages_to_overwrite;
+
+ /*
+ * Status of the file in the source.
+ */
+ bool source_exists;
+ file_type_t source_type;
+ size_t source_size;
+ char *source_link_target; /* for a symlink */
+
+ /*
+ * What will we do to the file?
+ */
+ file_action_t action;
+} file_entry_t;
+
+/*
+ * This contains the final decisions on what to do with each file.
+ * 'entries' array contains an entry for each file, sorted in the order
+ * that their actions should executed.
+ */
+typedef struct filemap_t
+{
+ /* Summary information, filled by calculate_totals() */
+ uint64 total_size; /* total size of the source cluster */
+ uint64 fetch_size; /* number of bytes that needs to be copied */
+
+ int nentries; /* size of 'entries' array */
+ file_entry_t *entries[FLEXIBLE_ARRAY_MEMBER];
+} filemap_t;
+
+/* Functions for populating the filemap */
+extern void filehash_init(void);
+extern void process_source_file(const char *path, file_type_t type,
+ size_t size, const char *link_target);
+extern void process_target_file(const char *path, file_type_t type,
+ size_t size, const char *link_target);
+extern void process_target_wal_block_change(ForkNumber forknum,
+ RelFileNode rnode,
+ BlockNumber blkno);
+
+extern filemap_t *decide_file_actions(void);
+extern void calculate_totals(filemap_t *filemap);
+extern void print_filemap(filemap_t *filemap);
+
+#endif /* FILEMAP_H */
diff --git a/src/bin/pg_rewind/libpq_source.c b/src/bin/pg_rewind/libpq_source.c
new file mode 100644
index 0000000..011c9cc
--- /dev/null
+++ b/src/bin/pg_rewind/libpq_source.c
@@ -0,0 +1,675 @@
+/*-------------------------------------------------------------------------
+ *
+ * libpq_source.c
+ * Functions for fetching files from a remote server via libpq.
+ *
+ * Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include "catalog/pg_type_d.h"
+#include "common/connect.h"
+#include "datapagemap.h"
+#include "file_ops.h"
+#include "filemap.h"
+#include "lib/stringinfo.h"
+#include "pg_rewind.h"
+#include "port/pg_bswap.h"
+#include "rewind_source.h"
+
+/*
+ * Files are fetched MAX_CHUNK_SIZE bytes at a time, and with a
+ * maximum of MAX_CHUNKS_PER_QUERY chunks in a single query.
+ */
+#define MAX_CHUNK_SIZE (1024 * 1024)
+#define MAX_CHUNKS_PER_QUERY 1000
+
+/* represents a request to fetch a piece of a file from the source */
+typedef struct
+{
+ const char *path; /* path relative to data directory root */
+ off_t offset;
+ size_t length;
+} fetch_range_request;
+
+typedef struct
+{
+ rewind_source common; /* common interface functions */
+
+ PGconn *conn;
+
+ /*
+ * Queue of chunks that have been requested with the queue_fetch_range()
+ * function, but have not been fetched from the remote server yet.
+ */
+ int num_requests;
+ fetch_range_request request_queue[MAX_CHUNKS_PER_QUERY];
+
+ /* temporary space for process_queued_fetch_requests() */
+ StringInfoData paths;
+ StringInfoData offsets;
+ StringInfoData lengths;
+} libpq_source;
+
+static void init_libpq_conn(PGconn *conn);
+static char *run_simple_query(PGconn *conn, const char *sql);
+static void run_simple_command(PGconn *conn, const char *sql);
+static void appendArrayEscapedString(StringInfo buf, const char *str);
+
+static void process_queued_fetch_requests(libpq_source *src);
+
+/* public interface functions */
+static void libpq_traverse_files(rewind_source *source,
+ process_file_callback_t callback);
+static void libpq_queue_fetch_file(rewind_source *source, const char *path, size_t len);
+static void libpq_queue_fetch_range(rewind_source *source, const char *path,
+ off_t off, size_t len);
+static void libpq_finish_fetch(rewind_source *source);
+static char *libpq_fetch_file(rewind_source *source, const char *path,
+ size_t *filesize);
+static XLogRecPtr libpq_get_current_wal_insert_lsn(rewind_source *source);
+static void libpq_destroy(rewind_source *source);
+
+/*
+ * Create a new libpq source.
+ *
+ * The caller has already established the connection, but should not try
+ * to use it while the source is active.
+ */
+rewind_source *
+init_libpq_source(PGconn *conn)
+{
+ libpq_source *src;
+
+ init_libpq_conn(conn);
+
+ src = pg_malloc0(sizeof(libpq_source));
+
+ src->common.traverse_files = libpq_traverse_files;
+ src->common.fetch_file = libpq_fetch_file;
+ src->common.queue_fetch_file = libpq_queue_fetch_file;
+ src->common.queue_fetch_range = libpq_queue_fetch_range;
+ src->common.finish_fetch = libpq_finish_fetch;
+ src->common.get_current_wal_insert_lsn = libpq_get_current_wal_insert_lsn;
+ src->common.destroy = libpq_destroy;
+
+ src->conn = conn;
+
+ initStringInfo(&src->paths);
+ initStringInfo(&src->offsets);
+ initStringInfo(&src->lengths);
+
+ return &src->common;
+}
+
+/*
+ * Initialize a libpq connection for use.
+ */
+static void
+init_libpq_conn(PGconn *conn)
+{
+ PGresult *res;
+ char *str;
+
+ /* disable all types of timeouts */
+ run_simple_command(conn, "SET statement_timeout = 0");
+ run_simple_command(conn, "SET lock_timeout = 0");
+ run_simple_command(conn, "SET idle_in_transaction_session_timeout = 0");
+
+ /*
+ * we don't intend to do any updates, put the connection in read-only mode
+ * to keep us honest
+ */
+ run_simple_command(conn, "SET default_transaction_read_only = on");
+
+ /* secure search_path */
+ res = PQexec(conn, ALWAYS_SECURE_SEARCH_PATH_SQL);
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ pg_fatal("could not clear search_path: %s",
+ PQresultErrorMessage(res));
+ PQclear(res);
+
+ /*
+ * Also check that full_page_writes is enabled. We can get torn pages if
+ * a page is modified while we read it with pg_read_binary_file(), and we
+ * rely on full page images to fix them.
+ */
+ str = run_simple_query(conn, "SHOW full_page_writes");
+ if (strcmp(str, "on") != 0)
+ pg_fatal("full_page_writes must be enabled in the source server");
+ pg_free(str);
+
+ /* Prepare a statement we'll use to fetch files */
+ res = PQprepare(conn, "fetch_chunks_stmt",
+ "SELECT path, begin,\n"
+ " pg_read_binary_file(path, begin, len, true) AS chunk\n"
+ "FROM unnest ($1::text[], $2::int8[], $3::int4[]) as x(path, begin, len)",
+ 3, NULL);
+
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ pg_fatal("could not prepare statement to fetch file contents: %s",
+ PQresultErrorMessage(res));
+ PQclear(res);
+}
+
+/*
+ * Run a query that returns a single value.
+ *
+ * The result should be pg_free'd after use.
+ */
+static char *
+run_simple_query(PGconn *conn, const char *sql)
+{
+ PGresult *res;
+ char *result;
+
+ res = PQexec(conn, sql);
+
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ pg_fatal("error running query (%s) on source server: %s",
+ sql, PQresultErrorMessage(res));
+
+ /* sanity check the result set */
+ if (PQnfields(res) != 1 || PQntuples(res) != 1 || PQgetisnull(res, 0, 0))
+ pg_fatal("unexpected result set from query");
+
+ result = pg_strdup(PQgetvalue(res, 0, 0));
+
+ PQclear(res);
+
+ return result;
+}
+
+/*
+ * Run a command.
+ *
+ * In the event of a failure, exit immediately.
+ */
+static void
+run_simple_command(PGconn *conn, const char *sql)
+{
+ PGresult *res;
+
+ res = PQexec(conn, sql);
+
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ pg_fatal("error running query (%s) in source server: %s",
+ sql, PQresultErrorMessage(res));
+
+ PQclear(res);
+}
+
+/*
+ * Call the pg_current_wal_insert_lsn() function in the remote system.
+ */
+static XLogRecPtr
+libpq_get_current_wal_insert_lsn(rewind_source *source)
+{
+ PGconn *conn = ((libpq_source *) source)->conn;
+ XLogRecPtr result;
+ uint32 hi;
+ uint32 lo;
+ char *val;
+
+ val = run_simple_query(conn, "SELECT pg_current_wal_insert_lsn()");
+
+ if (sscanf(val, "%X/%X", &hi, &lo) != 2)
+ pg_fatal("unrecognized result \"%s\" for current WAL insert location", val);
+
+ result = ((uint64) hi) << 32 | lo;
+
+ pg_free(val);
+
+ return result;
+}
+
+/*
+ * Get a list of all files in the data directory.
+ */
+static void
+libpq_traverse_files(rewind_source *source, process_file_callback_t callback)
+{
+ PGconn *conn = ((libpq_source *) source)->conn;
+ PGresult *res;
+ const char *sql;
+ int i;
+
+ /*
+ * Create a recursive directory listing of the whole data directory.
+ *
+ * The WITH RECURSIVE part does most of the work. The second part gets the
+ * targets of the symlinks in pg_tblspc directory.
+ *
+ * XXX: There is no backend function to get a symbolic link's target in
+ * general, so if the admin has put any custom symbolic links in the data
+ * directory, they won't be copied correctly.
+ */
+ sql =
+ "WITH RECURSIVE files (path, filename, size, isdir) AS (\n"
+ " SELECT '' AS path, filename, size, isdir FROM\n"
+ " (SELECT pg_ls_dir('.', true, false) AS filename) AS fn,\n"
+ " pg_stat_file(fn.filename, true) AS this\n"
+ " UNION ALL\n"
+ " SELECT parent.path || parent.filename || '/' AS path,\n"
+ " fn, this.size, this.isdir\n"
+ " FROM files AS parent,\n"
+ " pg_ls_dir(parent.path || parent.filename, true, false) AS fn,\n"
+ " pg_stat_file(parent.path || parent.filename || '/' || fn, true) AS this\n"
+ " WHERE parent.isdir = 't'\n"
+ ")\n"
+ "SELECT path || filename, size, isdir,\n"
+ " pg_tablespace_location(pg_tablespace.oid) AS link_target\n"
+ "FROM files\n"
+ "LEFT OUTER JOIN pg_tablespace ON files.path = 'pg_tblspc/'\n"
+ " AND oid::text = files.filename\n";
+ res = PQexec(conn, sql);
+
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ pg_fatal("could not fetch file list: %s",
+ PQresultErrorMessage(res));
+
+ /* sanity check the result set */
+ if (PQnfields(res) != 4)
+ pg_fatal("unexpected result set while fetching file list");
+
+ /* Read result to local variables */
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ char *path;
+ int64 filesize;
+ bool isdir;
+ char *link_target;
+ file_type_t type;
+
+ if (PQgetisnull(res, i, 1))
+ {
+ /*
+ * The file was removed from the server while the query was
+ * running. Ignore it.
+ */
+ continue;
+ }
+
+ path = PQgetvalue(res, i, 0);
+ filesize = atol(PQgetvalue(res, i, 1));
+ isdir = (strcmp(PQgetvalue(res, i, 2), "t") == 0);
+ link_target = PQgetvalue(res, i, 3);
+
+ if (link_target[0])
+ type = FILE_TYPE_SYMLINK;
+ else if (isdir)
+ type = FILE_TYPE_DIRECTORY;
+ else
+ type = FILE_TYPE_REGULAR;
+
+ process_source_file(path, type, filesize, link_target);
+ }
+ PQclear(res);
+}
+
+/*
+ * Queue up a request to fetch a file from remote system.
+ */
+static void
+libpq_queue_fetch_file(rewind_source *source, const char *path, size_t len)
+{
+ /*
+ * Truncate the target file immediately, and queue a request to fetch it
+ * from the source. If the file is small, smaller than MAX_CHUNK_SIZE,
+ * request fetching a full-sized chunk anyway, so that if the file has
+ * become larger in the source system, after we scanned the source
+ * directory, we still fetch the whole file. This only works for files up
+ * to MAX_CHUNK_SIZE, but that's good enough for small configuration files
+ * and such that are changed every now and then, but not WAL-logged. For
+ * larger files, we fetch up to the original size.
+ *
+ * Even with that mechanism, there is an inherent race condition if the
+ * file is modified at the same instant that we're copying it, so that we
+ * might copy a torn version of the file with one half from the old
+ * version and another half from the new. But pg_basebackup has the same
+ * problem, and it hasn't been a problem in practice.
+ *
+ * It might seem more natural to truncate the file later, when we receive
+ * it from the source server, but then we'd need to track which
+ * fetch-requests are for a whole file.
+ */
+ open_target_file(path, true);
+ libpq_queue_fetch_range(source, path, 0, Max(len, MAX_CHUNK_SIZE));
+}
+
+/*
+ * Queue up a request to fetch a piece of a file from remote system.
+ */
+static void
+libpq_queue_fetch_range(rewind_source *source, const char *path, off_t off,
+ size_t len)
+{
+ libpq_source *src = (libpq_source *) source;
+
+ /*
+ * Does this request happen to be a continuation of the previous chunk? If
+ * so, merge it with the previous one.
+ *
+ * XXX: We use pointer equality to compare the path. That's good enough
+ * for our purposes; the caller always passes the same pointer for the
+ * same filename. If it didn't, we would fail to merge requests, but it
+ * wouldn't affect correctness.
+ */
+ if (src->num_requests > 0)
+ {
+ fetch_range_request *prev = &src->request_queue[src->num_requests - 1];
+
+ if (prev->offset + prev->length == off &&
+ prev->length < MAX_CHUNK_SIZE &&
+ prev->path == path)
+ {
+ /*
+ * Extend the previous request to cover as much of this new
+ * request as possible, without exceeding MAX_CHUNK_SIZE.
+ */
+ size_t thislen;
+
+ thislen = Min(len, MAX_CHUNK_SIZE - prev->length);
+ prev->length += thislen;
+
+ off += thislen;
+ len -= thislen;
+
+ /*
+ * Fall through to create new requests for any remaining 'len'
+ * that didn't fit in the previous chunk.
+ */
+ }
+ }
+
+ /* Divide the request into pieces of MAX_CHUNK_SIZE bytes each */
+ while (len > 0)
+ {
+ int32 thislen;
+
+ /* if the queue is full, perform all the work queued up so far */
+ if (src->num_requests == MAX_CHUNKS_PER_QUERY)
+ process_queued_fetch_requests(src);
+
+ thislen = Min(len, MAX_CHUNK_SIZE);
+ src->request_queue[src->num_requests].path = path;
+ src->request_queue[src->num_requests].offset = off;
+ src->request_queue[src->num_requests].length = thislen;
+ src->num_requests++;
+
+ off += thislen;
+ len -= thislen;
+ }
+}
+
+/*
+ * Fetch all the queued chunks and write them to the target data directory.
+ */
+static void
+libpq_finish_fetch(rewind_source *source)
+{
+ process_queued_fetch_requests((libpq_source *) source);
+}
+
+static void
+process_queued_fetch_requests(libpq_source *src)
+{
+ const char *params[3];
+ PGresult *res;
+ int chunkno;
+
+ if (src->num_requests == 0)
+ return;
+
+ pg_log_debug("getting %d file chunks", src->num_requests);
+
+ /*
+ * The prepared statement, 'fetch_chunks_stmt', takes three arrays with
+ * the same length as parameters: paths, offsets and lengths. Construct
+ * the string representations of them.
+ */
+ resetStringInfo(&src->paths);
+ resetStringInfo(&src->offsets);
+ resetStringInfo(&src->lengths);
+
+ appendStringInfoChar(&src->paths, '{');
+ appendStringInfoChar(&src->offsets, '{');
+ appendStringInfoChar(&src->lengths, '{');
+ for (int i = 0; i < src->num_requests; i++)
+ {
+ fetch_range_request *rq = &src->request_queue[i];
+
+ if (i > 0)
+ {
+ appendStringInfoChar(&src->paths, ',');
+ appendStringInfoChar(&src->offsets, ',');
+ appendStringInfoChar(&src->lengths, ',');
+ }
+
+ appendArrayEscapedString(&src->paths, rq->path);
+ appendStringInfo(&src->offsets, INT64_FORMAT, (int64) rq->offset);
+ appendStringInfo(&src->lengths, INT64_FORMAT, (int64) rq->length);
+ }
+ appendStringInfoChar(&src->paths, '}');
+ appendStringInfoChar(&src->offsets, '}');
+ appendStringInfoChar(&src->lengths, '}');
+
+ /*
+ * Execute the prepared statement.
+ */
+ params[0] = src->paths.data;
+ params[1] = src->offsets.data;
+ params[2] = src->lengths.data;
+
+ if (PQsendQueryPrepared(src->conn, "fetch_chunks_stmt", 3, params, NULL, NULL, 1) != 1)
+ pg_fatal("could not send query: %s", PQerrorMessage(src->conn));
+
+ if (PQsetSingleRowMode(src->conn) != 1)
+ pg_fatal("could not set libpq connection to single row mode");
+
+ /*----
+ * The result set is of format:
+ *
+ * path text -- path in the data directory, e.g "base/1/123"
+ * begin int8 -- offset within the file
+ * chunk bytea -- file content
+ *----
+ */
+ chunkno = 0;
+ while ((res = PQgetResult(src->conn)) != NULL)
+ {
+ fetch_range_request *rq = &src->request_queue[chunkno];
+ char *filename;
+ int filenamelen;
+ int64 chunkoff;
+ int chunksize;
+ char *chunk;
+
+ switch (PQresultStatus(res))
+ {
+ case PGRES_SINGLE_TUPLE:
+ break;
+
+ case PGRES_TUPLES_OK:
+ PQclear(res);
+ continue; /* final zero-row result */
+
+ default:
+ pg_fatal("unexpected result while fetching remote files: %s",
+ PQresultErrorMessage(res));
+ }
+
+ if (chunkno > src->num_requests)
+ pg_fatal("received more data chunks than requested");
+
+ /* sanity check the result set */
+ if (PQnfields(res) != 3 || PQntuples(res) != 1)
+ pg_fatal("unexpected result set size while fetching remote files");
+
+ if (PQftype(res, 0) != TEXTOID ||
+ PQftype(res, 1) != INT8OID ||
+ PQftype(res, 2) != BYTEAOID)
+ {
+ pg_fatal("unexpected data types in result set while fetching remote files: %u %u %u",
+ PQftype(res, 0), PQftype(res, 1), PQftype(res, 2));
+ }
+
+ if (PQfformat(res, 0) != 1 &&
+ PQfformat(res, 1) != 1 &&
+ PQfformat(res, 2) != 1)
+ {
+ pg_fatal("unexpected result format while fetching remote files");
+ }
+
+ if (PQgetisnull(res, 0, 0) ||
+ PQgetisnull(res, 0, 1))
+ {
+ pg_fatal("unexpected null values in result while fetching remote files");
+ }
+
+ if (PQgetlength(res, 0, 1) != sizeof(int64))
+ pg_fatal("unexpected result length while fetching remote files");
+
+ /* Read result set to local variables */
+ memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int64));
+ chunkoff = pg_ntoh64(chunkoff);
+ chunksize = PQgetlength(res, 0, 2);
+
+ filenamelen = PQgetlength(res, 0, 0);
+ filename = pg_malloc(filenamelen + 1);
+ memcpy(filename, PQgetvalue(res, 0, 0), filenamelen);
+ filename[filenamelen] = '\0';
+
+ chunk = PQgetvalue(res, 0, 2);
+
+ /*
+ * If a file has been deleted on the source, remove it on the target
+ * as well. Note that multiple unlink() calls may happen on the same
+ * file if multiple data chunks are associated with it, hence ignore
+ * unconditionally anything missing.
+ */
+ if (PQgetisnull(res, 0, 2))
+ {
+ pg_log_debug("received null value for chunk for file \"%s\", file has been deleted",
+ filename);
+ remove_target_file(filename, true);
+ }
+ else
+ {
+ pg_log_debug("received chunk for file \"%s\", offset %lld, size %d",
+ filename, (long long int) chunkoff, chunksize);
+
+ if (strcmp(filename, rq->path) != 0)
+ {
+ pg_fatal("received data for file \"%s\", when requested for \"%s\"",
+ filename, rq->path);
+ }
+ if (chunkoff != rq->offset)
+ pg_fatal("received data at offset %lld of file \"%s\", when requested for offset %lld",
+ (long long int) chunkoff, rq->path, (long long int) rq->offset);
+
+ /*
+ * We should not receive more data than we requested, or
+ * pg_read_binary_file() messed up. We could receive less,
+ * though, if the file was truncated in the source after we
+ * checked its size. That's OK, there should be a WAL record of
+ * the truncation, which will get replayed when you start the
+ * target system for the first time after pg_rewind has completed.
+ */
+ if (chunksize > rq->length)
+ pg_fatal("received more than requested for file \"%s\"", rq->path);
+
+ open_target_file(filename, false);
+
+ write_target_range(chunk, chunkoff, chunksize);
+ }
+
+ pg_free(filename);
+
+ PQclear(res);
+ chunkno++;
+ }
+ if (chunkno != src->num_requests)
+ pg_fatal("unexpected number of data chunks received");
+
+ src->num_requests = 0;
+}
+
+/*
+ * Escape a string to be used as element in a text array constant
+ */
+static void
+appendArrayEscapedString(StringInfo buf, const char *str)
+{
+ appendStringInfoCharMacro(buf, '\"');
+ while (*str)
+ {
+ char ch = *str;
+
+ if (ch == '"' || ch == '\\')
+ appendStringInfoCharMacro(buf, '\\');
+
+ appendStringInfoCharMacro(buf, ch);
+
+ str++;
+ }
+ appendStringInfoCharMacro(buf, '\"');
+}
+
+/*
+ * Fetch a single file as a malloc'd buffer.
+ */
+static char *
+libpq_fetch_file(rewind_source *source, const char *path, size_t *filesize)
+{
+ PGconn *conn = ((libpq_source *) source)->conn;
+ PGresult *res;
+ char *result;
+ int len;
+ const char *paramValues[1];
+
+ paramValues[0] = path;
+ res = PQexecParams(conn, "SELECT pg_read_binary_file($1)",
+ 1, NULL, paramValues, NULL, NULL, 1);
+
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ pg_fatal("could not fetch remote file \"%s\": %s",
+ path, PQresultErrorMessage(res));
+
+ /* sanity check the result set */
+ if (PQntuples(res) != 1 || PQgetisnull(res, 0, 0))
+ pg_fatal("unexpected result set while fetching remote file \"%s\"",
+ path);
+
+ /* Read result to local variables */
+ len = PQgetlength(res, 0, 0);
+ result = pg_malloc(len + 1);
+ memcpy(result, PQgetvalue(res, 0, 0), len);
+ result[len] = '\0';
+
+ PQclear(res);
+
+ pg_log_debug("fetched file \"%s\", length %d", path, len);
+
+ if (filesize)
+ *filesize = len;
+ return result;
+}
+
+/*
+ * Close a libpq source.
+ */
+static void
+libpq_destroy(rewind_source *source)
+{
+ libpq_source *src = (libpq_source *) source;
+
+ pfree(src->paths.data);
+ pfree(src->offsets.data);
+ pfree(src->lengths.data);
+ pfree(src);
+
+ /* NOTE: we don't close the connection here, as it was not opened by us. */
+}
diff --git a/src/bin/pg_rewind/local_source.c b/src/bin/pg_rewind/local_source.c
new file mode 100644
index 0000000..2e50485
--- /dev/null
+++ b/src/bin/pg_rewind/local_source.c
@@ -0,0 +1,187 @@
+/*-------------------------------------------------------------------------
+ *
+ * local_source.c
+ * Functions for using a local data directory as the source.
+ *
+ * Portions Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "datapagemap.h"
+#include "file_ops.h"
+#include "filemap.h"
+#include "pg_rewind.h"
+#include "rewind_source.h"
+
+typedef struct
+{
+ rewind_source common; /* common interface functions */
+
+ const char *datadir; /* path to the source data directory */
+} local_source;
+
+static void local_traverse_files(rewind_source *source,
+ process_file_callback_t callback);
+static char *local_fetch_file(rewind_source *source, const char *path,
+ size_t *filesize);
+static void local_queue_fetch_file(rewind_source *source, const char *path,
+ size_t len);
+static void local_queue_fetch_range(rewind_source *source, const char *path,
+ off_t off, size_t len);
+static void local_finish_fetch(rewind_source *source);
+static void local_destroy(rewind_source *source);
+
+rewind_source *
+init_local_source(const char *datadir)
+{
+ local_source *src;
+
+ src = pg_malloc0(sizeof(local_source));
+
+ src->common.traverse_files = local_traverse_files;
+ src->common.fetch_file = local_fetch_file;
+ src->common.queue_fetch_file = local_queue_fetch_file;
+ src->common.queue_fetch_range = local_queue_fetch_range;
+ src->common.finish_fetch = local_finish_fetch;
+ src->common.get_current_wal_insert_lsn = NULL;
+ src->common.destroy = local_destroy;
+
+ src->datadir = datadir;
+
+ return &src->common;
+}
+
+static void
+local_traverse_files(rewind_source *source, process_file_callback_t callback)
+{
+ traverse_datadir(((local_source *) source)->datadir, &process_source_file);
+}
+
+static char *
+local_fetch_file(rewind_source *source, const char *path, size_t *filesize)
+{
+ return slurpFile(((local_source *) source)->datadir, path, filesize);
+}
+
+/*
+ * Copy a file from source to target.
+ *
+ * 'len' is the expected length of the file.
+ */
+static void
+local_queue_fetch_file(rewind_source *source, const char *path, size_t len)
+{
+ const char *datadir = ((local_source *) source)->datadir;
+ PGAlignedBlock buf;
+ char srcpath[MAXPGPATH];
+ int srcfd;
+ size_t written_len;
+
+ snprintf(srcpath, sizeof(srcpath), "%s/%s", datadir, path);
+
+ /* Open source file for reading */
+ srcfd = open(srcpath, O_RDONLY | PG_BINARY, 0);
+ if (srcfd < 0)
+ pg_fatal("could not open source file \"%s\": %m",
+ srcpath);
+
+ /* Truncate and open the target file for writing */
+ open_target_file(path, true);
+
+ written_len = 0;
+ for (;;)
+ {
+ ssize_t read_len;
+
+ read_len = read(srcfd, buf.data, sizeof(buf));
+
+ if (read_len < 0)
+ pg_fatal("could not read file \"%s\": %m", srcpath);
+ else if (read_len == 0)
+ break; /* EOF reached */
+
+ write_target_range(buf.data, written_len, read_len);
+ written_len += read_len;
+ }
+
+ /*
+ * A local source is not expected to change while we're rewinding, so
+ * check that the size of the file matches our earlier expectation.
+ */
+ if (written_len != len)
+ pg_fatal("size of source file \"%s\" changed concurrently: %d bytes expected, %d copied",
+ srcpath, (int) len, (int) written_len);
+
+ if (close(srcfd) != 0)
+ pg_fatal("could not close file \"%s\": %m", srcpath);
+}
+
+/*
+ * Copy a file from source to target, starting at 'off', for 'len' bytes.
+ */
+static void
+local_queue_fetch_range(rewind_source *source, const char *path, off_t off,
+ size_t len)
+{
+ const char *datadir = ((local_source *) source)->datadir;
+ PGAlignedBlock buf;
+ char srcpath[MAXPGPATH];
+ int srcfd;
+ off_t begin = off;
+ off_t end = off + len;
+
+ snprintf(srcpath, sizeof(srcpath), "%s/%s", datadir, path);
+
+ srcfd = open(srcpath, O_RDONLY | PG_BINARY, 0);
+ if (srcfd < 0)
+ pg_fatal("could not open source file \"%s\": %m",
+ srcpath);
+
+ if (lseek(srcfd, begin, SEEK_SET) == -1)
+ pg_fatal("could not seek in source file: %m");
+
+ open_target_file(path, false);
+
+ while (end - begin > 0)
+ {
+ ssize_t readlen;
+ size_t thislen;
+
+ if (end - begin > sizeof(buf))
+ thislen = sizeof(buf);
+ else
+ thislen = end - begin;
+
+ readlen = read(srcfd, buf.data, thislen);
+
+ if (readlen < 0)
+ pg_fatal("could not read file \"%s\": %m", srcpath);
+ else if (readlen == 0)
+ pg_fatal("unexpected EOF while reading file \"%s\"", srcpath);
+
+ write_target_range(buf.data, begin, readlen);
+ begin += readlen;
+ }
+
+ if (close(srcfd) != 0)
+ pg_fatal("could not close file \"%s\": %m", srcpath);
+}
+
+static void
+local_finish_fetch(rewind_source *source)
+{
+ /*
+ * Nothing to do, local_queue_fetch_range() copies the ranges immediately.
+ */
+}
+
+static void
+local_destroy(rewind_source *source)
+{
+ pfree(source);
+}
diff --git a/src/bin/pg_rewind/nls.mk b/src/bin/pg_rewind/nls.mk
new file mode 100644
index 0000000..31123b9
--- /dev/null
+++ b/src/bin/pg_rewind/nls.mk
@@ -0,0 +1,7 @@
+# src/bin/pg_rewind/nls.mk
+CATALOG_NAME = pg_rewind
+AVAIL_LANGUAGES = de el es fr it ja ka ko ru sv uk zh_CN
+GETTEXT_FILES = $(FRONTEND_COMMON_GETTEXT_FILES) datapagemap.c file_ops.c filemap.c libpq_source.c local_source.c parsexlog.c pg_rewind.c timeline.c xlogreader.c ../../common/fe_memutils.c ../../common/restricted_token.c ../../fe_utils/archive.c ../../fe_utils/recovery_gen.c
+GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) report_invalid_record:2
+GETTEXT_FLAGS = $(FRONTEND_COMMON_GETTEXT_FLAGS) \
+ report_invalid_record:2:c-format
diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c
new file mode 100644
index 0000000..c6792da
--- /dev/null
+++ b/src/bin/pg_rewind/parsexlog.c
@@ -0,0 +1,462 @@
+/*-------------------------------------------------------------------------
+ *
+ * parsexlog.c
+ * Functions for reading Write-Ahead-Log
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include <unistd.h>
+
+#include "access/rmgr.h"
+#include "access/xact.h"
+#include "access/xlog_internal.h"
+#include "access/xlogreader.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
+#include "commands/dbcommands_xlog.h"
+#include "fe_utils/archive.h"
+#include "filemap.h"
+#include "pg_rewind.h"
+
+/*
+ * RmgrNames is an array of the built-in resource manager names, to make error
+ * messages a bit nicer.
+ */
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup,mask,decode) \
+ name,
+
+static const char *RmgrNames[RM_MAX_ID + 1] = {
+#include "access/rmgrlist.h"
+};
+
+#define RmgrName(rmid) (((rmid) <= RM_MAX_BUILTIN_ID) ? \
+ RmgrNames[rmid] : "custom")
+
+static void extractPageInfo(XLogReaderState *record);
+
+static int xlogreadfd = -1;
+static XLogSegNo xlogreadsegno = 0;
+static char xlogfpath[MAXPGPATH];
+
+typedef struct XLogPageReadPrivate
+{
+ const char *restoreCommand;
+ int tliIndex;
+} XLogPageReadPrivate;
+
+static int SimpleXLogPageRead(XLogReaderState *xlogreader,
+ XLogRecPtr targetPagePtr,
+ int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
+
+/*
+ * Read WAL from the datadir/pg_wal, starting from 'startpoint' on timeline
+ * index 'tliIndex' in target timeline history, until 'endpoint'. Make note of
+ * the data blocks touched by the WAL records, and return them in a page map.
+ *
+ * 'endpoint' is the end of the last record to read. The record starting at
+ * 'endpoint' is the first one that is not read.
+ */
+void
+extractPageMap(const char *datadir, XLogRecPtr startpoint, int tliIndex,
+ XLogRecPtr endpoint, const char *restoreCommand)
+{
+ XLogRecord *record;
+ XLogReaderState *xlogreader;
+ char *errormsg;
+ XLogPageReadPrivate private;
+
+ private.tliIndex = tliIndex;
+ private.restoreCommand = restoreCommand;
+ xlogreader = XLogReaderAllocate(WalSegSz, datadir,
+ XL_ROUTINE(.page_read = &SimpleXLogPageRead),
+ &private);
+ if (xlogreader == NULL)
+ pg_fatal("out of memory while allocating a WAL reading processor");
+
+ XLogBeginRead(xlogreader, startpoint);
+ do
+ {
+ record = XLogReadRecord(xlogreader, &errormsg);
+
+ if (record == NULL)
+ {
+ XLogRecPtr errptr = xlogreader->EndRecPtr;
+
+ if (errormsg)
+ pg_fatal("could not read WAL record at %X/%X: %s",
+ LSN_FORMAT_ARGS(errptr),
+ errormsg);
+ else
+ pg_fatal("could not read WAL record at %X/%X",
+ LSN_FORMAT_ARGS(errptr));
+ }
+
+ extractPageInfo(xlogreader);
+ } while (xlogreader->EndRecPtr < endpoint);
+
+ /*
+ * If 'endpoint' didn't point exactly at a record boundary, the caller
+ * messed up.
+ */
+ if (xlogreader->EndRecPtr != endpoint)
+ pg_fatal("end pointer %X/%X is not a valid end point; expected %X/%X",
+ LSN_FORMAT_ARGS(endpoint), LSN_FORMAT_ARGS(xlogreader->EndRecPtr));
+
+ XLogReaderFree(xlogreader);
+ if (xlogreadfd != -1)
+ {
+ close(xlogreadfd);
+ xlogreadfd = -1;
+ }
+}
+
+/*
+ * Reads one WAL record. Returns the end position of the record, without
+ * doing anything with the record itself.
+ */
+XLogRecPtr
+readOneRecord(const char *datadir, XLogRecPtr ptr, int tliIndex,
+ const char *restoreCommand)
+{
+ XLogRecord *record;
+ XLogReaderState *xlogreader;
+ char *errormsg;
+ XLogPageReadPrivate private;
+ XLogRecPtr endptr;
+
+ private.tliIndex = tliIndex;
+ private.restoreCommand = restoreCommand;
+ xlogreader = XLogReaderAllocate(WalSegSz, datadir,
+ XL_ROUTINE(.page_read = &SimpleXLogPageRead),
+ &private);
+ if (xlogreader == NULL)
+ pg_fatal("out of memory while allocating a WAL reading processor");
+
+ XLogBeginRead(xlogreader, ptr);
+ record = XLogReadRecord(xlogreader, &errormsg);
+ if (record == NULL)
+ {
+ if (errormsg)
+ pg_fatal("could not read WAL record at %X/%X: %s",
+ LSN_FORMAT_ARGS(ptr), errormsg);
+ else
+ pg_fatal("could not read WAL record at %X/%X",
+ LSN_FORMAT_ARGS(ptr));
+ }
+ endptr = xlogreader->EndRecPtr;
+
+ XLogReaderFree(xlogreader);
+ if (xlogreadfd != -1)
+ {
+ close(xlogreadfd);
+ xlogreadfd = -1;
+ }
+
+ return endptr;
+}
+
+/*
+ * Find the previous checkpoint preceding given WAL location.
+ */
+void
+findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex,
+ XLogRecPtr *lastchkptrec, TimeLineID *lastchkpttli,
+ XLogRecPtr *lastchkptredo, const char *restoreCommand)
+{
+ /* Walk backwards, starting from the given record */
+ XLogRecord *record;
+ XLogRecPtr searchptr;
+ XLogReaderState *xlogreader;
+ char *errormsg;
+ XLogPageReadPrivate private;
+
+ /*
+ * The given fork pointer points to the end of the last common record,
+ * which is not necessarily the beginning of the next record, if the
+ * previous record happens to end at a page boundary. Skip over the page
+ * header in that case to find the next record.
+ */
+ if (forkptr % XLOG_BLCKSZ == 0)
+ {
+ if (XLogSegmentOffset(forkptr, WalSegSz) == 0)
+ forkptr += SizeOfXLogLongPHD;
+ else
+ forkptr += SizeOfXLogShortPHD;
+ }
+
+ private.tliIndex = tliIndex;
+ private.restoreCommand = restoreCommand;
+ xlogreader = XLogReaderAllocate(WalSegSz, datadir,
+ XL_ROUTINE(.page_read = &SimpleXLogPageRead),
+ &private);
+ if (xlogreader == NULL)
+ pg_fatal("out of memory while allocating a WAL reading processor");
+
+ searchptr = forkptr;
+ for (;;)
+ {
+ uint8 info;
+
+ XLogBeginRead(xlogreader, searchptr);
+ record = XLogReadRecord(xlogreader, &errormsg);
+
+ if (record == NULL)
+ {
+ if (errormsg)
+ pg_fatal("could not find previous WAL record at %X/%X: %s",
+ LSN_FORMAT_ARGS(searchptr),
+ errormsg);
+ else
+ pg_fatal("could not find previous WAL record at %X/%X",
+ LSN_FORMAT_ARGS(searchptr));
+ }
+
+ /*
+ * Check if it is a checkpoint record. This checkpoint record needs to
+ * be the latest checkpoint before WAL forked and not the checkpoint
+ * where the primary has been stopped to be rewound.
+ */
+ info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
+ if (searchptr < forkptr &&
+ XLogRecGetRmid(xlogreader) == RM_XLOG_ID &&
+ (info == XLOG_CHECKPOINT_SHUTDOWN ||
+ info == XLOG_CHECKPOINT_ONLINE))
+ {
+ CheckPoint checkPoint;
+
+ memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
+ *lastchkptrec = searchptr;
+ *lastchkpttli = checkPoint.ThisTimeLineID;
+ *lastchkptredo = checkPoint.redo;
+ break;
+ }
+
+ /* Walk backwards to previous record. */
+ searchptr = record->xl_prev;
+ }
+
+ XLogReaderFree(xlogreader);
+ if (xlogreadfd != -1)
+ {
+ close(xlogreadfd);
+ xlogreadfd = -1;
+ }
+}
+
+/* XLogReader callback function, to read a WAL page */
+static int
+SimpleXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
+ int reqLen, XLogRecPtr targetRecPtr, char *readBuf)
+{
+ XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
+ uint32 targetPageOff;
+ XLogRecPtr targetSegEnd;
+ XLogSegNo targetSegNo;
+ int r;
+
+ XLByteToSeg(targetPagePtr, targetSegNo, WalSegSz);
+ XLogSegNoOffsetToRecPtr(targetSegNo + 1, 0, WalSegSz, targetSegEnd);
+ targetPageOff = XLogSegmentOffset(targetPagePtr, WalSegSz);
+
+ /*
+ * See if we need to switch to a new segment because the requested record
+ * is not in the currently open one.
+ */
+ if (xlogreadfd >= 0 &&
+ !XLByteInSeg(targetPagePtr, xlogreadsegno, WalSegSz))
+ {
+ close(xlogreadfd);
+ xlogreadfd = -1;
+ }
+
+ XLByteToSeg(targetPagePtr, xlogreadsegno, WalSegSz);
+
+ if (xlogreadfd < 0)
+ {
+ char xlogfname[MAXFNAMELEN];
+
+ /*
+ * Since incomplete segments are copied into next timelines, switch to
+ * the timeline holding the required segment. Assuming this scan can
+ * be done both forward and backward, consider also switching timeline
+ * accordingly.
+ */
+ while (private->tliIndex < targetNentries - 1 &&
+ targetHistory[private->tliIndex].end < targetSegEnd)
+ private->tliIndex++;
+ while (private->tliIndex > 0 &&
+ targetHistory[private->tliIndex].begin >= targetSegEnd)
+ private->tliIndex--;
+
+ XLogFileName(xlogfname, targetHistory[private->tliIndex].tli,
+ xlogreadsegno, WalSegSz);
+
+ snprintf(xlogfpath, MAXPGPATH, "%s/" XLOGDIR "/%s",
+ xlogreader->segcxt.ws_dir, xlogfname);
+
+ xlogreadfd = open(xlogfpath, O_RDONLY | PG_BINARY, 0);
+
+ if (xlogreadfd < 0)
+ {
+ /*
+ * If we have no restore_command to execute, then exit.
+ */
+ if (private->restoreCommand == NULL)
+ {
+ pg_log_error("could not open file \"%s\": %m", xlogfpath);
+ return -1;
+ }
+
+ /*
+ * Since we have restore_command, then try to retrieve missing WAL
+ * file from the archive.
+ */
+ xlogreadfd = RestoreArchivedFile(xlogreader->segcxt.ws_dir,
+ xlogfname,
+ WalSegSz,
+ private->restoreCommand);
+
+ if (xlogreadfd < 0)
+ return -1;
+ else
+ pg_log_debug("using file \"%s\" restored from archive",
+ xlogfpath);
+ }
+ }
+
+ /*
+ * At this point, we have the right segment open.
+ */
+ Assert(xlogreadfd != -1);
+
+ /* Read the requested page */
+ if (lseek(xlogreadfd, (off_t) targetPageOff, SEEK_SET) < 0)
+ {
+ pg_log_error("could not seek in file \"%s\": %m", xlogfpath);
+ return -1;
+ }
+
+
+ r = read(xlogreadfd, readBuf, XLOG_BLCKSZ);
+ if (r != XLOG_BLCKSZ)
+ {
+ if (r < 0)
+ pg_log_error("could not read file \"%s\": %m", xlogfpath);
+ else
+ pg_log_error("could not read file \"%s\": read %d of %zu",
+ xlogfpath, r, (Size) XLOG_BLCKSZ);
+
+ return -1;
+ }
+
+ Assert(targetSegNo == xlogreadsegno);
+
+ xlogreader->seg.ws_tli = targetHistory[private->tliIndex].tli;
+ return XLOG_BLCKSZ;
+}
+
+/*
+ * Extract information on which blocks the current record modifies.
+ */
+static void
+extractPageInfo(XLogReaderState *record)
+{
+ int block_id;
+ RmgrId rmid = XLogRecGetRmid(record);
+ uint8 info = XLogRecGetInfo(record);
+ uint8 rminfo = info & ~XLR_INFO_MASK;
+
+ /* Is this a special record type that I recognize? */
+
+ if (rmid == RM_DBASE_ID && rminfo == XLOG_DBASE_CREATE_FILE_COPY)
+ {
+ /*
+ * New databases can be safely ignored. It won't be present in the
+ * source system, so it will be deleted. There's one corner-case,
+ * though: if a new, different, database is also created in the source
+ * system, we'll see that the files already exist and not copy them.
+ * That's OK, though; WAL replay of creating the new database, from
+ * the source systems's WAL, will re-copy the new database,
+ * overwriting the database created in the target system.
+ */
+ }
+ else if (rmid == RM_DBASE_ID && rminfo == XLOG_DBASE_CREATE_WAL_LOG)
+ {
+ /*
+ * New databases can be safely ignored. It won't be present in the
+ * source system, so it will be deleted.
+ */
+ }
+ else if (rmid == RM_DBASE_ID && rminfo == XLOG_DBASE_DROP)
+ {
+ /*
+ * An existing database was dropped. We'll see that the files don't
+ * exist in the target data dir, and copy them in toto from the source
+ * system. No need to do anything special here.
+ */
+ }
+ else if (rmid == RM_SMGR_ID && rminfo == XLOG_SMGR_CREATE)
+ {
+ /*
+ * We can safely ignore these. The file will be removed from the
+ * target, if it doesn't exist in source system. If a file with same
+ * name is created in source system, too, there will be WAL records
+ * for all the blocks in it.
+ */
+ }
+ else if (rmid == RM_SMGR_ID && rminfo == XLOG_SMGR_TRUNCATE)
+ {
+ /*
+ * We can safely ignore these. When we compare the sizes later on,
+ * we'll notice that they differ, and copy the missing tail from
+ * source system.
+ */
+ }
+ else if (rmid == RM_XACT_ID &&
+ ((rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_COMMIT ||
+ (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_COMMIT_PREPARED ||
+ (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_ABORT ||
+ (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_ABORT_PREPARED))
+ {
+ /*
+ * These records can include "dropped rels". We can safely ignore
+ * them, we will see that they are missing and copy them from the
+ * source.
+ */
+ }
+ else if (info & XLR_SPECIAL_REL_UPDATE)
+ {
+ /*
+ * This record type modifies a relation file in some special way, but
+ * we don't recognize the type. That's bad - we don't know how to
+ * track that change.
+ */
+ pg_fatal("WAL record modifies a relation, but record type is not recognized: "
+ "lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X",
+ LSN_FORMAT_ARGS(record->ReadRecPtr),
+ rmid, RmgrName(rmid), info);
+ }
+
+ for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
+ {
+ RelFileNode rnode;
+ ForkNumber forknum;
+ BlockNumber blkno;
+
+ if (!XLogRecGetBlockTagExtended(record, block_id,
+ &rnode, &forknum, &blkno, NULL))
+ continue;
+
+ /* We only care about the main fork; others are copied in toto */
+ if (forknum != MAIN_FORKNUM)
+ continue;
+
+ process_target_wal_block_change(forknum, rnode, blkno);
+ }
+}
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
new file mode 100644
index 0000000..1ff8da1
--- /dev/null
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -0,0 +1,1169 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_rewind.c
+ * Synchronizes a PostgreSQL data directory to a new timeline
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "access/timeline.h"
+#include "access/xlog_internal.h"
+#include "catalog/catversion.h"
+#include "catalog/pg_control.h"
+#include "common/controldata_utils.h"
+#include "common/file_perm.h"
+#include "common/restricted_token.h"
+#include "common/string.h"
+#include "fe_utils/recovery_gen.h"
+#include "fe_utils/string_utils.h"
+#include "file_ops.h"
+#include "filemap.h"
+#include "getopt_long.h"
+#include "pg_rewind.h"
+#include "rewind_source.h"
+#include "storage/bufpage.h"
+
+static void usage(const char *progname);
+
+static void perform_rewind(filemap_t *filemap, rewind_source *source,
+ XLogRecPtr chkptrec,
+ TimeLineID chkpttli,
+ XLogRecPtr chkptredo);
+
+static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli,
+ XLogRecPtr checkpointloc);
+
+static void digestControlFile(ControlFileData *ControlFile,
+ const char *content, size_t size);
+static void getRestoreCommand(const char *argv0);
+static void sanityChecks(void);
+static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex);
+static void ensureCleanShutdown(const char *argv0);
+static void disconnect_atexit(void);
+
+static ControlFileData ControlFile_target;
+static ControlFileData ControlFile_source;
+static ControlFileData ControlFile_source_after;
+
+const char *progname;
+int WalSegSz;
+
+/* Configuration options */
+char *datadir_target = NULL;
+char *datadir_source = NULL;
+char *connstr_source = NULL;
+char *restore_command = NULL;
+char *config_file = NULL;
+
+static bool debug = false;
+bool showprogress = false;
+bool dry_run = false;
+bool do_sync = true;
+bool restore_wal = false;
+
+/* Target history */
+TimeLineHistoryEntry *targetHistory;
+int targetNentries;
+
+/* Progress counters */
+uint64 fetch_size;
+uint64 fetch_done;
+
+static PGconn *conn;
+static rewind_source *source;
+
+static void
+usage(const char *progname)
+{
+ printf(_("%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"), progname);
+ printf(_("Usage:\n %s [OPTION]...\n\n"), progname);
+ printf(_("Options:\n"));
+ printf(_(" -c, --restore-target-wal use restore_command in target configuration to\n"
+ " retrieve WAL files from archives\n"));
+ printf(_(" -D, --target-pgdata=DIRECTORY existing data directory to modify\n"));
+ printf(_(" --source-pgdata=DIRECTORY source data directory to synchronize with\n"));
+ printf(_(" --source-server=CONNSTR source server to synchronize with\n"));
+ printf(_(" -n, --dry-run stop before modifying anything\n"));
+ printf(_(" -N, --no-sync do not wait for changes to be written\n"
+ " safely to disk\n"));
+ printf(_(" -P, --progress write progress messages\n"));
+ printf(_(" -R, --write-recovery-conf write configuration for replication\n"
+ " (requires --source-server)\n"));
+ printf(_(" --config-file=FILENAME use specified main server configuration\n"
+ " file when running target cluster\n"));
+ printf(_(" --debug write a lot of debug messages\n"));
+ printf(_(" --no-ensure-shutdown do not automatically fix unclean shutdown\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);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ static struct option long_options[] = {
+ {"help", no_argument, NULL, '?'},
+ {"target-pgdata", required_argument, NULL, 'D'},
+ {"write-recovery-conf", no_argument, NULL, 'R'},
+ {"source-pgdata", required_argument, NULL, 1},
+ {"source-server", required_argument, NULL, 2},
+ {"no-ensure-shutdown", no_argument, NULL, 4},
+ {"config-file", required_argument, NULL, 5},
+ {"version", no_argument, NULL, 'V'},
+ {"restore-target-wal", no_argument, NULL, 'c'},
+ {"dry-run", no_argument, NULL, 'n'},
+ {"no-sync", no_argument, NULL, 'N'},
+ {"progress", no_argument, NULL, 'P'},
+ {"debug", no_argument, NULL, 3},
+ {NULL, 0, NULL, 0}
+ };
+ int option_index;
+ int c;
+ XLogRecPtr divergerec;
+ int lastcommontliIndex;
+ XLogRecPtr chkptrec;
+ TimeLineID chkpttli;
+ XLogRecPtr chkptredo;
+ XLogRecPtr target_wal_endrec;
+ size_t size;
+ char *buffer;
+ bool no_ensure_shutdown = false;
+ bool rewind_needed;
+ bool writerecoveryconf = false;
+ filemap_t *filemap;
+
+ pg_logging_init(argv[0]);
+ set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_rewind"));
+ progname = get_progname(argv[0]);
+
+ /* Process command-line arguments */
+ if (argc > 1)
+ {
+ if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
+ {
+ usage(progname);
+ exit(0);
+ }
+ if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
+ {
+ puts("pg_rewind (PostgreSQL) " PG_VERSION);
+ exit(0);
+ }
+ }
+
+ while ((c = getopt_long(argc, argv, "cD:nNPR", long_options, &option_index)) != -1)
+ {
+ switch (c)
+ {
+ case 'c':
+ restore_wal = true;
+ break;
+
+ case 'P':
+ showprogress = true;
+ break;
+
+ case 'n':
+ dry_run = true;
+ break;
+
+ case 'N':
+ do_sync = false;
+ break;
+
+ case 'R':
+ writerecoveryconf = true;
+ break;
+
+ case 3:
+ debug = true;
+ pg_logging_increase_verbosity();
+ break;
+
+ case 'D': /* -D or --target-pgdata */
+ datadir_target = pg_strdup(optarg);
+ break;
+
+ case 1: /* --source-pgdata */
+ datadir_source = pg_strdup(optarg);
+ break;
+
+ case 2: /* --source-server */
+ connstr_source = pg_strdup(optarg);
+ break;
+
+ case 4:
+ no_ensure_shutdown = true;
+ break;
+
+ case 5:
+ config_file = pg_strdup(optarg);
+ break;
+
+ default:
+ /* getopt_long already emitted a complaint */
+ pg_log_error_hint("Try \"%s --help\" for more information.", progname);
+ exit(1);
+ }
+ }
+
+ if (datadir_source == NULL && connstr_source == NULL)
+ {
+ pg_log_error("no source specified (--source-pgdata or --source-server)");
+ pg_log_error_hint("Try \"%s --help\" for more information.", progname);
+ exit(1);
+ }
+
+ if (datadir_source != NULL && connstr_source != NULL)
+ {
+ pg_log_error("only one of --source-pgdata or --source-server can be specified");
+ pg_log_error_hint("Try \"%s --help\" for more information.", progname);
+ exit(1);
+ }
+
+ if (datadir_target == NULL)
+ {
+ pg_log_error("no target data directory specified (--target-pgdata)");
+ pg_log_error_hint("Try \"%s --help\" for more information.", progname);
+ exit(1);
+ }
+
+ if (writerecoveryconf && connstr_source == NULL)
+ {
+ pg_log_error("no source server information (--source-server) specified for --write-recovery-conf");
+ pg_log_error_hint("Try \"%s --help\" for more information.", progname);
+ exit(1);
+ }
+
+ 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);
+ }
+
+ /*
+ * Don't allow pg_rewind to be run as root, to avoid overwriting the
+ * ownership of files in the data directory. We need only check for root
+ * -- any other user won't have sufficient permissions to modify files in
+ * the data directory.
+ */
+#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();
+
+ /* Set mask based on PGDATA permissions */
+ if (!GetDataDirectoryCreatePerm(datadir_target))
+ pg_fatal("could not read permissions of directory \"%s\": %m",
+ datadir_target);
+
+ umask(pg_mode_mask);
+
+ getRestoreCommand(argv[0]);
+
+ atexit(disconnect_atexit);
+
+ /*
+ * Ok, we have all the options and we're ready to start. First, connect to
+ * remote server.
+ */
+ if (connstr_source)
+ {
+ conn = PQconnectdb(connstr_source);
+
+ if (PQstatus(conn) == CONNECTION_BAD)
+ pg_fatal("%s", PQerrorMessage(conn));
+
+ if (showprogress)
+ pg_log_info("connected to server");
+
+ source = init_libpq_source(conn);
+ }
+ else
+ source = init_local_source(datadir_source);
+
+ /*
+ * Check the status of the target instance.
+ *
+ * If the target instance was not cleanly shut down, start and stop the
+ * target cluster once in single-user mode to enforce recovery to finish,
+ * ensuring that the cluster can be used by pg_rewind. Note that if
+ * no_ensure_shutdown is specified, pg_rewind ignores this step, and users
+ * need to make sure by themselves that the target cluster is in a clean
+ * state.
+ */
+ buffer = slurpFile(datadir_target, "global/pg_control", &size);
+ digestControlFile(&ControlFile_target, buffer, size);
+ pg_free(buffer);
+
+ if (!no_ensure_shutdown &&
+ ControlFile_target.state != DB_SHUTDOWNED &&
+ ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
+ {
+ ensureCleanShutdown(argv[0]);
+
+ buffer = slurpFile(datadir_target, "global/pg_control", &size);
+ digestControlFile(&ControlFile_target, buffer, size);
+ pg_free(buffer);
+ }
+
+ buffer = source->fetch_file(source, "global/pg_control", &size);
+ digestControlFile(&ControlFile_source, buffer, size);
+ pg_free(buffer);
+
+ sanityChecks();
+
+ /*
+ * Find the common ancestor timeline between the clusters.
+ *
+ * If both clusters are already on the same timeline, there's nothing to
+ * do.
+ */
+ if (ControlFile_target.checkPointCopy.ThisTimeLineID ==
+ ControlFile_source.checkPointCopy.ThisTimeLineID)
+ {
+ pg_log_info("source and target cluster are on the same timeline");
+ rewind_needed = false;
+ target_wal_endrec = 0;
+ }
+ else
+ {
+ XLogRecPtr chkptendrec;
+
+ findCommonAncestorTimeline(&divergerec, &lastcommontliIndex);
+ pg_log_info("servers diverged at WAL location %X/%X on timeline %u",
+ LSN_FORMAT_ARGS(divergerec),
+ targetHistory[lastcommontliIndex].tli);
+
+ /*
+ * Determine the end-of-WAL on the target.
+ *
+ * The WAL ends at the last shutdown checkpoint, or at
+ * minRecoveryPoint if it was a standby. (If we supported rewinding a
+ * server that was not shut down cleanly, we would need to replay
+ * until we reach the first invalid record, like crash recovery does.)
+ */
+
+ /* read the checkpoint record on the target to see where it ends. */
+ chkptendrec = readOneRecord(datadir_target,
+ ControlFile_target.checkPoint,
+ targetNentries - 1,
+ restore_command);
+
+ if (ControlFile_target.minRecoveryPoint > chkptendrec)
+ {
+ target_wal_endrec = ControlFile_target.minRecoveryPoint;
+ }
+ else
+ {
+ target_wal_endrec = chkptendrec;
+ }
+
+ /*
+ * Check for the possibility that the target is in fact a direct
+ * ancestor of the source. In that case, there is no divergent history
+ * in the target that needs rewinding.
+ */
+ if (target_wal_endrec > divergerec)
+ {
+ rewind_needed = true;
+ }
+ else
+ {
+ /* the last common checkpoint record must be part of target WAL */
+ Assert(target_wal_endrec == divergerec);
+
+ rewind_needed = false;
+ }
+ }
+
+ if (!rewind_needed)
+ {
+ pg_log_info("no rewind required");
+ if (writerecoveryconf && !dry_run)
+ WriteRecoveryConfig(conn, datadir_target,
+ GenerateRecoveryConfig(conn, NULL));
+ exit(0);
+ }
+
+ findLastCheckpoint(datadir_target, divergerec, lastcommontliIndex,
+ &chkptrec, &chkpttli, &chkptredo, restore_command);
+ pg_log_info("rewinding from last common checkpoint at %X/%X on timeline %u",
+ LSN_FORMAT_ARGS(chkptrec), chkpttli);
+
+ /* Initialize the hash table to track the status of each file */
+ filehash_init();
+
+ /*
+ * Collect information about all files in the both data directories.
+ */
+ if (showprogress)
+ pg_log_info("reading source file list");
+ source->traverse_files(source, &process_source_file);
+
+ if (showprogress)
+ pg_log_info("reading target file list");
+ traverse_datadir(datadir_target, &process_target_file);
+
+ /*
+ * Read the target WAL from last checkpoint before the point of fork, to
+ * extract all the pages that were modified on the target cluster after
+ * the fork.
+ */
+ if (showprogress)
+ pg_log_info("reading WAL in target");
+ extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
+ target_wal_endrec, restore_command);
+
+ /*
+ * We have collected all information we need from both systems. Decide
+ * what to do with each file.
+ */
+ filemap = decide_file_actions();
+ if (showprogress)
+ calculate_totals(filemap);
+
+ /* this is too verbose even for verbose mode */
+ if (debug)
+ print_filemap(filemap);
+
+ /*
+ * Ok, we're ready to start copying things over.
+ */
+ if (showprogress)
+ {
+ pg_log_info("need to copy %lu MB (total source directory size is %lu MB)",
+ (unsigned long) (filemap->fetch_size / (1024 * 1024)),
+ (unsigned long) (filemap->total_size / (1024 * 1024)));
+
+ fetch_size = filemap->fetch_size;
+ fetch_done = 0;
+ }
+
+ /*
+ * We have now collected all the information we need from both systems,
+ * and we are ready to start modifying the target directory.
+ *
+ * This is the point of no return. Once we start copying things, there is
+ * no turning back!
+ */
+ perform_rewind(filemap, source, chkptrec, chkpttli, chkptredo);
+
+ if (showprogress)
+ pg_log_info("syncing target data directory");
+ sync_target_dir();
+
+ /* Also update the standby configuration, if requested. */
+ if (writerecoveryconf && !dry_run)
+ WriteRecoveryConfig(conn, datadir_target,
+ GenerateRecoveryConfig(conn, NULL));
+
+ /* don't need the source connection anymore */
+ source->destroy(source);
+ if (conn)
+ {
+ PQfinish(conn);
+ conn = NULL;
+ }
+
+ pg_log_info("Done!");
+
+ return 0;
+}
+
+/*
+ * Perform the rewind.
+ *
+ * We have already collected all the information we need from the
+ * target and the source.
+ */
+static void
+perform_rewind(filemap_t *filemap, rewind_source *source,
+ XLogRecPtr chkptrec,
+ TimeLineID chkpttli,
+ XLogRecPtr chkptredo)
+{
+ XLogRecPtr endrec;
+ TimeLineID endtli;
+ ControlFileData ControlFile_new;
+ size_t size;
+ char *buffer;
+
+ /*
+ * Execute the actions in the file map, fetching data from the source
+ * system as needed.
+ */
+ for (int i = 0; i < filemap->nentries; i++)
+ {
+ file_entry_t *entry = filemap->entries[i];
+
+ /*
+ * If this is a relation file, copy the modified blocks.
+ *
+ * This is in addition to any other changes.
+ */
+ if (entry->target_pages_to_overwrite.bitmapsize > 0)
+ {
+ datapagemap_iterator_t *iter;
+ BlockNumber blkno;
+ off_t offset;
+
+ iter = datapagemap_iterate(&entry->target_pages_to_overwrite);
+ while (datapagemap_next(iter, &blkno))
+ {
+ offset = blkno * BLCKSZ;
+ source->queue_fetch_range(source, entry->path, offset, BLCKSZ);
+ }
+ pg_free(iter);
+ }
+
+ switch (entry->action)
+ {
+ case FILE_ACTION_NONE:
+ /* nothing else to do */
+ break;
+
+ case FILE_ACTION_COPY:
+ source->queue_fetch_file(source, entry->path, entry->source_size);
+ break;
+
+ case FILE_ACTION_TRUNCATE:
+ truncate_target_file(entry->path, entry->source_size);
+ break;
+
+ case FILE_ACTION_COPY_TAIL:
+ source->queue_fetch_range(source, entry->path,
+ entry->target_size,
+ entry->source_size - entry->target_size);
+ break;
+
+ case FILE_ACTION_REMOVE:
+ remove_target(entry);
+ break;
+
+ case FILE_ACTION_CREATE:
+ create_target(entry);
+ break;
+
+ case FILE_ACTION_UNDECIDED:
+ pg_fatal("no action decided for file \"%s\"", entry->path);
+ break;
+ }
+ }
+
+ /* Complete any remaining range-fetches that we queued up above. */
+ source->finish_fetch(source);
+
+ close_target_file();
+
+ progress_report(true);
+
+ /*
+ * Fetch the control file from the source last. This ensures that the
+ * minRecoveryPoint is up-to-date.
+ */
+ buffer = source->fetch_file(source, "global/pg_control", &size);
+ digestControlFile(&ControlFile_source_after, buffer, size);
+ pg_free(buffer);
+
+ /*
+ * Sanity check: If the source is a local system, the control file should
+ * not have changed since we started.
+ *
+ * XXX: We assume it hasn't been modified, but actually, what could go
+ * wrong? The logic handles a libpq source that's modified concurrently,
+ * why not a local datadir?
+ */
+ if (datadir_source &&
+ memcmp(&ControlFile_source, &ControlFile_source_after,
+ sizeof(ControlFileData)) != 0)
+ {
+ pg_fatal("source system was modified while pg_rewind was running");
+ }
+
+ if (showprogress)
+ pg_log_info("creating backup label and updating control file");
+
+ /*
+ * Create a backup label file, to tell the target where to begin the WAL
+ * replay. Normally, from the last common checkpoint between the source
+ * and the target. But if the source is a standby server, it's possible
+ * that the last common checkpoint is *after* the standby's restartpoint.
+ * That implies that the source server has applied the checkpoint record,
+ * but hasn't performed a corresponding restartpoint yet. Make sure we
+ * start at the restartpoint's redo point in that case.
+ *
+ * Use the old version of the source's control file for this. The server
+ * might have finished the restartpoint after we started copying files,
+ * but we must begin from the redo point at the time that started copying.
+ */
+ if (ControlFile_source.checkPointCopy.redo < chkptredo)
+ {
+ chkptredo = ControlFile_source.checkPointCopy.redo;
+ chkpttli = ControlFile_source.checkPointCopy.ThisTimeLineID;
+ chkptrec = ControlFile_source.checkPoint;
+ }
+ createBackupLabel(chkptredo, chkpttli, chkptrec);
+
+ /*
+ * Update control file of target, to tell the target how far it must
+ * replay the WAL (minRecoveryPoint).
+ */
+ if (connstr_source)
+ {
+ /*
+ * The source is a live server. Like in an online backup, it's
+ * important that we recover all the WAL that was generated while we
+ * were copying files.
+ */
+ if (ControlFile_source_after.state == DB_IN_ARCHIVE_RECOVERY)
+ {
+ /*
+ * Source is a standby server. We must replay to its
+ * minRecoveryPoint.
+ */
+ endrec = ControlFile_source_after.minRecoveryPoint;
+ endtli = ControlFile_source_after.minRecoveryPointTLI;
+ }
+ else
+ {
+ /*
+ * Source is a production, non-standby, server. We must replay to
+ * the last WAL insert location.
+ */
+ if (ControlFile_source_after.state != DB_IN_PRODUCTION)
+ pg_fatal("source system was in unexpected state at end of rewind");
+
+ endrec = source->get_current_wal_insert_lsn(source);
+ endtli = ControlFile_source_after.checkPointCopy.ThisTimeLineID;
+ }
+ }
+ else
+ {
+ /*
+ * Source is a local data directory. It should've shut down cleanly,
+ * and we must replay to the latest shutdown checkpoint.
+ */
+ endrec = ControlFile_source_after.checkPoint;
+ endtli = ControlFile_source_after.checkPointCopy.ThisTimeLineID;
+ }
+
+ memcpy(&ControlFile_new, &ControlFile_source_after, sizeof(ControlFileData));
+ ControlFile_new.minRecoveryPoint = endrec;
+ ControlFile_new.minRecoveryPointTLI = endtli;
+ ControlFile_new.state = DB_IN_ARCHIVE_RECOVERY;
+ if (!dry_run)
+ update_controlfile(datadir_target, &ControlFile_new, do_sync);
+}
+
+static void
+sanityChecks(void)
+{
+ /* TODO Check that there's no backup_label in either cluster */
+
+ /* Check system_identifier match */
+ if (ControlFile_target.system_identifier != ControlFile_source.system_identifier)
+ pg_fatal("source and target clusters are from different systems");
+
+ /* check version */
+ if (ControlFile_target.pg_control_version != PG_CONTROL_VERSION ||
+ ControlFile_source.pg_control_version != PG_CONTROL_VERSION ||
+ ControlFile_target.catalog_version_no != CATALOG_VERSION_NO ||
+ ControlFile_source.catalog_version_no != CATALOG_VERSION_NO)
+ {
+ pg_fatal("clusters are not compatible with this version of pg_rewind");
+ }
+
+ /*
+ * Target cluster need to use checksums or hint bit wal-logging, this to
+ * prevent from data corruption that could occur because of hint bits.
+ */
+ if (ControlFile_target.data_checksum_version != PG_DATA_CHECKSUM_VERSION &&
+ !ControlFile_target.wal_log_hints)
+ {
+ pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"");
+ }
+
+ /*
+ * Target cluster better not be running. This doesn't guard against
+ * someone starting the cluster concurrently. Also, this is probably more
+ * strict than necessary; it's OK if the target node was not shut down
+ * cleanly, as long as it isn't running at the moment.
+ */
+ if (ControlFile_target.state != DB_SHUTDOWNED &&
+ ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
+ pg_fatal("target server must be shut down cleanly");
+
+ /*
+ * When the source is a data directory, also require that the source
+ * server is shut down. There isn't any very strong reason for this
+ * limitation, but better safe than sorry.
+ */
+ if (datadir_source &&
+ ControlFile_source.state != DB_SHUTDOWNED &&
+ ControlFile_source.state != DB_SHUTDOWNED_IN_RECOVERY)
+ pg_fatal("source data directory must be shut down cleanly");
+}
+
+/*
+ * Print a progress report based on the fetch_size and fetch_done variables.
+ *
+ * Progress report is written at maximum once per second, except that the
+ * last progress report is always printed.
+ *
+ * If finished is set to true, this is the last progress report. The cursor
+ * is moved to the next line.
+ */
+void
+progress_report(bool finished)
+{
+ static pg_time_t last_progress_report = 0;
+ int percent;
+ char fetch_done_str[32];
+ char fetch_size_str[32];
+ pg_time_t now;
+
+ if (!showprogress)
+ return;
+
+ now = time(NULL);
+ if (now == last_progress_report && !finished)
+ return; /* Max once per second */
+
+ last_progress_report = now;
+ percent = fetch_size ? (int) ((fetch_done) * 100 / fetch_size) : 0;
+
+ /*
+ * Avoid overflowing past 100% or the full size. This may make the total
+ * size number change as we approach the end of the backup (the estimate
+ * will always be wrong if WAL is included), but that's better than having
+ * the done column be bigger than the total.
+ */
+ if (percent > 100)
+ percent = 100;
+ if (fetch_done > fetch_size)
+ fetch_size = fetch_done;
+
+ snprintf(fetch_done_str, sizeof(fetch_done_str), UINT64_FORMAT,
+ fetch_done / 1024);
+ snprintf(fetch_size_str, sizeof(fetch_size_str), UINT64_FORMAT,
+ fetch_size / 1024);
+
+ fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
+ (int) strlen(fetch_size_str), fetch_done_str, fetch_size_str,
+ percent);
+
+ /*
+ * Stay on the same line if reporting to a terminal and we're not done
+ * yet.
+ */
+ fputc((!finished && isatty(fileno(stderr))) ? '\r' : '\n', stderr);
+}
+
+/*
+ * Find minimum from two WAL locations assuming InvalidXLogRecPtr means
+ * infinity as src/include/access/timeline.h states. This routine should
+ * be used only when comparing WAL locations related to history files.
+ */
+static XLogRecPtr
+MinXLogRecPtr(XLogRecPtr a, XLogRecPtr b)
+{
+ if (XLogRecPtrIsInvalid(a))
+ return b;
+ else if (XLogRecPtrIsInvalid(b))
+ return a;
+ else
+ return Min(a, b);
+}
+
+/*
+ * Retrieve timeline history for given control file which should behold
+ * either source or target.
+ */
+static TimeLineHistoryEntry *
+getTimelineHistory(ControlFileData *controlFile, int *nentries)
+{
+ TimeLineHistoryEntry *history;
+ TimeLineID tli;
+
+ tli = controlFile->checkPointCopy.ThisTimeLineID;
+
+ /*
+ * Timeline 1 does not have a history file, so there is no need to check
+ * and fake an entry with infinite start and end positions.
+ */
+ if (tli == 1)
+ {
+ history = (TimeLineHistoryEntry *) pg_malloc(sizeof(TimeLineHistoryEntry));
+ history->tli = tli;
+ history->begin = history->end = InvalidXLogRecPtr;
+ *nentries = 1;
+ }
+ else
+ {
+ char path[MAXPGPATH];
+ char *histfile;
+
+ TLHistoryFilePath(path, tli);
+
+ /* Get history file from appropriate source */
+ if (controlFile == &ControlFile_source)
+ histfile = source->fetch_file(source, path, NULL);
+ else if (controlFile == &ControlFile_target)
+ histfile = slurpFile(datadir_target, path, NULL);
+ else
+ pg_fatal("invalid control file");
+
+ history = rewind_parseTimeLineHistory(histfile, tli, nentries);
+ pg_free(histfile);
+ }
+
+ if (debug)
+ {
+ int i;
+
+ if (controlFile == &ControlFile_source)
+ pg_log_debug("Source timeline history:");
+ else if (controlFile == &ControlFile_target)
+ pg_log_debug("Target timeline history:");
+ else
+ Assert(false);
+
+ /*
+ * Print the target timeline history.
+ */
+ for (i = 0; i < targetNentries; i++)
+ {
+ TimeLineHistoryEntry *entry;
+
+ entry = &history[i];
+ pg_log_debug("%u: %X/%X - %X/%X", entry->tli,
+ LSN_FORMAT_ARGS(entry->begin),
+ LSN_FORMAT_ARGS(entry->end));
+ }
+ }
+
+ return history;
+}
+
+/*
+ * Determine the TLI of the last common timeline in the timeline history of the
+ * two clusters. targetHistory is filled with target timeline history and
+ * targetNentries is number of items in targetHistory. *tliIndex is set to the
+ * index of last common timeline in targetHistory array, and *recptr is set to
+ * the position where the timeline history diverged (ie. the first WAL record
+ * that's not the same in both clusters).
+ *
+ * Control files of both clusters must be read into ControlFile_target/source
+ * before calling this routine.
+ */
+static void
+findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex)
+{
+ TimeLineHistoryEntry *sourceHistory;
+ int sourceNentries;
+ int i,
+ n;
+
+ /* Retrieve timelines for both source and target */
+ sourceHistory = getTimelineHistory(&ControlFile_source, &sourceNentries);
+ targetHistory = getTimelineHistory(&ControlFile_target, &targetNentries);
+
+ /*
+ * Trace the history forward, until we hit the timeline diverge. It may
+ * still be possible that the source and target nodes used the same
+ * timeline number in their history but with different start position
+ * depending on the history files that each node has fetched in previous
+ * recovery processes. Hence check the start position of the new timeline
+ * as well and move down by one extra timeline entry if they do not match.
+ */
+ n = Min(sourceNentries, targetNentries);
+ for (i = 0; i < n; i++)
+ {
+ if (sourceHistory[i].tli != targetHistory[i].tli ||
+ sourceHistory[i].begin != targetHistory[i].begin)
+ break;
+ }
+
+ if (i > 0)
+ {
+ i--;
+ *recptr = MinXLogRecPtr(sourceHistory[i].end, targetHistory[i].end);
+ *tliIndex = i;
+
+ pg_free(sourceHistory);
+ return;
+ }
+ else
+ {
+ pg_fatal("could not find common ancestor of the source and target cluster's timelines");
+ }
+}
+
+
+/*
+ * Create a backup_label file that forces recovery to begin at the last common
+ * checkpoint.
+ */
+static void
+createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, XLogRecPtr checkpointloc)
+{
+ XLogSegNo startsegno;
+ time_t stamp_time;
+ char strfbuf[128];
+ char xlogfilename[MAXFNAMELEN];
+ struct tm *tmp;
+ char buf[1000];
+ int len;
+
+ XLByteToSeg(startpoint, startsegno, WalSegSz);
+ XLogFileName(xlogfilename, starttli, startsegno, WalSegSz);
+
+ /*
+ * Construct backup label file
+ */
+ stamp_time = time(NULL);
+ tmp = localtime(&stamp_time);
+ strftime(strfbuf, sizeof(strfbuf), "%Y-%m-%d %H:%M:%S %Z", tmp);
+
+ len = snprintf(buf, sizeof(buf),
+ "START WAL LOCATION: %X/%X (file %s)\n"
+ "CHECKPOINT LOCATION: %X/%X\n"
+ "BACKUP METHOD: pg_rewind\n"
+ "BACKUP FROM: standby\n"
+ "START TIME: %s\n",
+ /* omit LABEL: line */
+ LSN_FORMAT_ARGS(startpoint), xlogfilename,
+ LSN_FORMAT_ARGS(checkpointloc),
+ strfbuf);
+ if (len >= sizeof(buf))
+ pg_fatal("backup label buffer too small"); /* shouldn't happen */
+
+ /* TODO: move old file out of the way, if any. */
+ open_target_file("backup_label", true); /* BACKUP_LABEL_FILE */
+ write_target_range(buf, 0, len);
+ close_target_file();
+}
+
+/*
+ * Check CRC of control file
+ */
+static void
+checkControlFile(ControlFileData *ControlFile)
+{
+ pg_crc32c crc;
+
+ /* Calculate CRC */
+ INIT_CRC32C(crc);
+ COMP_CRC32C(crc, (char *) ControlFile, offsetof(ControlFileData, crc));
+ FIN_CRC32C(crc);
+
+ /* And simply compare it */
+ if (!EQ_CRC32C(crc, ControlFile->crc))
+ pg_fatal("unexpected control file CRC");
+}
+
+/*
+ * Verify control file contents in the buffer 'content', and copy it to
+ * *ControlFile.
+ */
+static void
+digestControlFile(ControlFileData *ControlFile, const char *content,
+ size_t size)
+{
+ if (size != PG_CONTROL_FILE_SIZE)
+ pg_fatal("unexpected control file size %d, expected %d",
+ (int) size, PG_CONTROL_FILE_SIZE);
+
+ memcpy(ControlFile, content, sizeof(ControlFileData));
+
+ /* set and validate WalSegSz */
+ WalSegSz = ControlFile->xlog_seg_size;
+
+ if (!IsValidWalSegSize(WalSegSz))
+ pg_fatal(ngettext("WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte",
+ "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes",
+ WalSegSz),
+ WalSegSz);
+
+ /* Additional checks on control file */
+ checkControlFile(ControlFile);
+}
+
+/*
+ * Get value of GUC parameter restore_command from the target cluster.
+ *
+ * This uses a logic based on "postgres -C" to get the value from the
+ * cluster.
+ */
+static void
+getRestoreCommand(const char *argv0)
+{
+ int rc;
+ char postgres_exec_path[MAXPGPATH],
+ cmd_output[MAXPGPATH];
+ PQExpBuffer postgres_cmd;
+
+ if (!restore_wal)
+ return;
+
+ /* find postgres executable */
+ rc = find_other_exec(argv0, "postgres",
+ PG_BACKEND_VERSIONSTR,
+ postgres_exec_path);
+
+ if (rc < 0)
+ {
+ char full_path[MAXPGPATH];
+
+ if (find_my_exec(argv0, full_path) < 0)
+ strlcpy(full_path, progname, sizeof(full_path));
+
+ if (rc == -1)
+ pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"",
+ "postgres", progname, full_path);
+ else
+ pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s",
+ "postgres", full_path, progname);
+ }
+
+ /*
+ * Build a command able to retrieve the value of GUC parameter
+ * restore_command, if set.
+ */
+ postgres_cmd = createPQExpBuffer();
+
+ /* path to postgres, properly quoted */
+ appendShellString(postgres_cmd, postgres_exec_path);
+
+ /* add -D switch, with properly quoted data directory */
+ appendPQExpBufferStr(postgres_cmd, " -D ");
+ appendShellString(postgres_cmd, datadir_target);
+
+ /* add custom configuration file only if requested */
+ if (config_file != NULL)
+ {
+ appendPQExpBufferStr(postgres_cmd, " -c config_file=");
+ appendShellString(postgres_cmd, config_file);
+ }
+
+ /* add -C switch, for restore_command */
+ appendPQExpBufferStr(postgres_cmd, " -C restore_command");
+
+ if (!pipe_read_line(postgres_cmd->data, cmd_output, sizeof(cmd_output)))
+ exit(1);
+
+ (void) pg_strip_crlf(cmd_output);
+
+ if (strcmp(cmd_output, "") == 0)
+ pg_fatal("restore_command is not set in the target cluster");
+
+ restore_command = pg_strdup(cmd_output);
+
+ pg_log_debug("using for rewind restore_command = \'%s\'",
+ restore_command);
+
+ destroyPQExpBuffer(postgres_cmd);
+}
+
+
+/*
+ * Ensure clean shutdown of target instance by launching single-user mode
+ * postgres to do crash recovery.
+ */
+static void
+ensureCleanShutdown(const char *argv0)
+{
+ int ret;
+#define MAXCMDLEN (2 * MAXPGPATH)
+ char exec_path[MAXPGPATH];
+ PQExpBuffer postgres_cmd;
+
+ /* locate postgres binary */
+ if ((ret = find_other_exec(argv0, "postgres",
+ PG_BACKEND_VERSIONSTR,
+ exec_path)) < 0)
+ {
+ char full_path[MAXPGPATH];
+
+ 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\"",
+ "postgres", progname, full_path);
+ else
+ pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s",
+ "postgres", full_path, progname);
+ }
+
+ pg_log_info("executing \"%s\" for target server to complete crash recovery",
+ exec_path);
+
+ /*
+ * Skip processing if requested, but only after ensuring presence of
+ * postgres.
+ */
+ if (dry_run)
+ return;
+
+ /*
+ * Finally run postgres in single-user mode. There is no need to use
+ * fsync here. This makes the recovery faster, and the target data folder
+ * is synced at the end anyway.
+ */
+ postgres_cmd = createPQExpBuffer();
+
+ /* path to postgres, properly quoted */
+ appendShellString(postgres_cmd, exec_path);
+
+ /* add set of options with properly quoted data directory */
+ appendPQExpBufferStr(postgres_cmd, " --single -F -D ");
+ appendShellString(postgres_cmd, datadir_target);
+
+ /* add custom configuration file only if requested */
+ if (config_file != NULL)
+ {
+ appendPQExpBufferStr(postgres_cmd, " -c config_file=");
+ appendShellString(postgres_cmd, config_file);
+ }
+
+ /* finish with the database name, and a properly quoted redirection */
+ appendPQExpBufferStr(postgres_cmd, " template1 < ");
+ appendShellString(postgres_cmd, DEVNULL);
+
+ if (system(postgres_cmd->data) != 0)
+ {
+ pg_log_error("postgres single-user mode in target cluster failed");
+ pg_log_error_detail("Command was: %s", postgres_cmd->data);
+ exit(1);
+ }
+
+ destroyPQExpBuffer(postgres_cmd);
+}
+
+static void
+disconnect_atexit(void)
+{
+ if (conn != NULL)
+ PQfinish(conn);
+}
diff --git a/src/bin/pg_rewind/pg_rewind.h b/src/bin/pg_rewind/pg_rewind.h
new file mode 100644
index 0000000..393182f
--- /dev/null
+++ b/src/bin/pg_rewind/pg_rewind.h
@@ -0,0 +1,56 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_rewind.h
+ *
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_REWIND_H
+#define PG_REWIND_H
+
+#include "access/timeline.h"
+#include "common/logging.h"
+#include "datapagemap.h"
+#include "libpq-fe.h"
+#include "storage/block.h"
+#include "storage/relfilenode.h"
+
+/* Configuration options */
+extern char *datadir_target;
+extern bool showprogress;
+extern bool dry_run;
+extern bool do_sync;
+extern int WalSegSz;
+
+/* Target history */
+extern TimeLineHistoryEntry *targetHistory;
+extern int targetNentries;
+
+/* Progress counters */
+extern uint64 fetch_size;
+extern uint64 fetch_done;
+
+/* in parsexlog.c */
+extern void extractPageMap(const char *datadir, XLogRecPtr startpoint,
+ int tliIndex, XLogRecPtr endpoint,
+ const char *restoreCommand);
+extern void findLastCheckpoint(const char *datadir, XLogRecPtr searchptr,
+ int tliIndex,
+ XLogRecPtr *lastchkptrec, TimeLineID *lastchkpttli,
+ XLogRecPtr *lastchkptredo,
+ const char *restoreCommand);
+extern XLogRecPtr readOneRecord(const char *datadir, XLogRecPtr ptr,
+ int tliIndex, const char *restoreCommand);
+
+/* in pg_rewind.c */
+extern void progress_report(bool finished);
+
+/* in timeline.c */
+extern TimeLineHistoryEntry *rewind_parseTimeLineHistory(char *buffer,
+ TimeLineID targetTLI,
+ int *nentries);
+
+#endif /* PG_REWIND_H */
diff --git a/src/bin/pg_rewind/po/de.po b/src/bin/pg_rewind/po/de.po
new file mode 100644
index 0000000..07a32f5
--- /dev/null
+++ b/src/bin/pg_rewind/po/de.po
@@ -0,0 +1,1010 @@
+# German message translation file for pg_rewind
+# Copyright (C) 2015-2022 PostgreSQL Global Development Group
+# This file is distributed under the same license as the PostgreSQL package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL) 15\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2022-09-24 23:21+0000\n"
+"PO-Revision-Date: 2022-09-25 10:37+0200\n"
+"Last-Translator: Peter Eisentraut <peter@eisentraut.org>\n"
+"Language-Team: German <pgsql-translators@postgresql.org>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "Fehler: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "Warnung: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "Detail: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "Tipp: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "Speicher aufgebraucht\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "kann NULL-Zeiger nicht kopieren (interner Fehler)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "konnte Bibliothek »%s« nicht laden: Fehlercode %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "auf dieser Plattform können keine beschränkten Token erzeugt werden: Fehlercode %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "konnte Prozess-Token nicht öffnen: Fehlercode %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "konnte SIDs nicht erzeugen: Fehlercode %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "konnte beschränktes Token nicht erzeugen: Fehlercode %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "konnte Prozess für Befehl »%s« nicht starten: Fehlercode %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "konnte Prozess nicht mit beschränktem Token neu starten: Fehlercode %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "konnte Statuscode des Subprozesses nicht ermitteln: Fehlercode %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "kann restore_command mit Platzhalter %%r nicht verwenden"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "unerwartete Dateigröße für »%s«: %lld statt %lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "konnte aus dem Archiv wiederhergestellte Datei »%s« nicht öffnen: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "konnte »stat« für Datei »%s« nicht ausführen: %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "restore_command fehlgeschlagen: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "konnte Datei »%s« nicht aus Archiv wiederherstellen"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "Speicher aufgebraucht"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "konnte Datei »%s« nicht öffnen: %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "konnte nicht in Datei »%s« schreiben: %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "konnte Datei »%s« nicht erstellen: %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "konnte Zieldatei »%s« nicht öffnen: %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "konnte Zieldatei »%s« nicht schließen: %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "konnte Positionszeiger in Zieldatei »%s« nicht setzen: %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "konnte Datei »%s« nicht schreiben: %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "undefinierter Dateityp für »%s«"
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "ungültige Aktion (CREATE) für normale Datei"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "konnte Datei »%s« nicht löschen: %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "konnte Datei »%s« nicht zum Kürzen öffnen: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "konnte Datei »%s« nicht auf %u kürzen: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "konnte Verzeichnis »%s« nicht erzeugen: %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "konnte Verzeichnis »%s« nicht löschen: %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "konnte symbolische Verknüpfung »%s« nicht erstellen: %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "konnte symbolische Verknüpfung »%s« nicht löschen: %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "konnte Datei »%s« nicht zum Lesen öffnen: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "konnte Datei »%s« nicht lesen: %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "konnte Datei »%s« nicht lesen: %d von %zu gelesen"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "konnte Verzeichnis »%s« nicht öffnen: %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "konnte symbolische Verknüpfung »%s« nicht lesen: %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "Ziel für symbolische Verknüpfung »%s« ist zu lang"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "»%s« ist eine symbolische Verknüpfung, aber symbolische Verknüpfungen werden auf dieser Plattform nicht unterstützt"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "konnte Verzeichnis »%s« nicht lesen: %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "konnte Verzeichnis »%s« nicht schließen: %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "Datendatei »%s« in der Quelle ist keine normale Datei"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "doppelte Quelldatei »%s«"
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "unerwartete Seitenänderung für nicht normale Datei »%s«"
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "unbekannter Dateityp für »%s«"
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "Datei »%s« hat unterschiedlichen Typ in Quelle und Ziel"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "konnte nicht entscheiden, was mit Datei »%s« zu tun ist"
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "konnte search_path nicht auf leer setzen: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "full_page_writes muss im Quell-Server eingeschaltet sein"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "konnte Anfrage zum Holen des Dateiinhalts nicht vorbereiten: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "Fehler beim Ausführen einer Anfrage (%s) auf dem Quellserver: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "Anfrage ergab unerwartete Ergebnismenge"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "Fehler beim Ausführen einer Anfrage (%s) im Quellserver: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "unbekanntes Ergebnis »%s« für aktuelle WAL-Einfügeposition"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "konnte Dateiliste nicht holen: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "unerwartete Ergebnismenge beim Holen der Dateiliste"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "konnte Anfrage nicht senden: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "konnte libpq-Verbindung nicht in den Einzelzeilenmodus setzen"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "unerwartetes Ergebnis beim Holen von fernen Dateien: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "mehr Daten-Chunks erhalten als verlangt"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "unerwartete Ergebnismengengröße beim Holen von fernen Dateien"
+
+#: libpq_source.c:515
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "unerwartete Datentypen in Ergebnismenge beim Holen von fernen Dateien: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "unerwartetes Ergebnisformat beim Holen von fernen Dateien"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "unerwartete NULL-Werte im Ergebnis beim Holen von fernen Dateien"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "unerwartete Ergebnislänge beim Holen von fernen Dateien"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "Daten für Datei »%s« erhalten, aber »%s« wurde verlangt"
+
+#: libpq_source.c:570
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "Daten für Offset %lld von Datei »%s« erhalten, aber Offset %lld wurde verlangt"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "mehr als verlangt erhalten für Datei »%s«"
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "unerwartete Anzahl Daten-Chunks erhalten"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "konnte ferne Datei »%s« nicht holen: %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "unerwartete Ergebnismenge beim Holen der fernen Datei »%s«"
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "konnte Quelldatei »%s« nicht öffnen: %m"
+
+#: local_source.c:117
+#, c-format
+msgid "size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "Größe der Quelldatei »%s« nebenläufig verändert: %d Bytes erwartet, %d kopiert"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "konnte Datei »%s« nicht schließen: %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "konnte Positionszeiger in Quelldatei nicht setzen: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "unerwartetes EOF beim Lesen der Datei »%s«"
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "Speicher aufgebraucht beim Anlegen eines WAL-Leseprozessors"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "konnte WAL-Eintrag bei %X/%X nicht lesen: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "konnte WAL-Eintrag bei %X/%X nicht lesen"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "Endpunkt %X/%X ist kein gültiger Endpunkt; %X/%X erwartet"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "konnte vorangegangenen WAL-Eintrag bei %X/%X nicht finden: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "konnte vorangegangenen WAL-Eintrag bei %X/%X nicht finden"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "konnte Positionszeiger in Datei »%s« nicht setzen: %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr "WAL-Eintrag modifiziert eine Relation, aber Typ des Eintrags wurde nicht erkannt: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s resynchronisiert einen PostgreSQL-Cluster mit einer Kopie des Clusters.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"Aufruf:\n"
+" %s [OPTION]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "Optionen:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal restore_command in der Zielkonfiguration zum\n"
+" Laden von WAL-Dateien aus Archiv verwenden\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=VERZ bestehendes zu modifizierendes Datenverzeichnis\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr ""
+" --source-pgdata=VERZ Quelldatenverzeichnis, mit dem synchronisiert\n"
+" werden soll\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=VERB Quellserver, mit dem synchronisiert werden soll\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run anhalten, bevor etwas geändert wird\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr ""
+" -N, --no-sync nicht warten, bis Änderungen sicher auf\n"
+" Festplatte geschrieben sind\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress Fortschrittsmeldungen ausgeben\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf Konfiguration für Replikation schreiben\n"
+" (benötigt --source-server)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=DATEINAME angegebene Serverkonfigurationsdatei zum\n"
+" Starten des Ziel-Clusters verwenden\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug viele Debug-Meldungen ausgeben\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr " --no-ensure-shutdown unsauberen Shutdown nicht automatisch reparieren\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version Versionsinformationen anzeigen, dann beenden\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help diese Hilfe anzeigen, dann beenden\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"Berichten Sie Fehler an <%s>.\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "%s Homepage: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "Versuchen Sie »%s --help« für weitere Informationen."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "keine Quelle angegeben (--source-pgdata oder --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "--source-pgdata und --source-server können nicht zusammen angegeben werden"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "kein Zielverzeichnis angegeben (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "kein Quellserver (--source-server) angegeben für --write-recovery-conf"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "zu viele Kommandozeilenargumente (das erste ist »%s«)"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "kann nicht von »root« ausgeführt werden"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "Sie müssen %s als PostgreSQL-Superuser ausführen."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "konnte Zugriffsrechte von Verzeichnis »%s« nicht lesen: %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "mit Server verbunden"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "Quell- und Ziel-Cluster sind auf der gleichen Zeitleiste"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "Server divergierten bei WAL-Position %X/%X auf Zeitleiste %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "kein Rückspulen nötig"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "Rückspulen ab letztem gemeinsamen Checkpoint bei %X/%X auf Zeitleiste %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "lese Quelldateiliste"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "lese Zieldateiliste"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "lese WAL im Ziel-Cluster"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "%lu MB müssen kopiert werden (Gesamtgröße des Quellverzeichnisses ist %lu MB)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "synchronisiere Zieldatenverzeichnis"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "Fertig!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "keine Aktion bestimmt für Datei »%s«"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "Quellsystem wurde verändert, während pg_rewind lief"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "erzeuge Backup-Label und aktualisiere Kontrolldatei"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "Quellsystem war in einem unerwarteten Zustand am Ende des Rückspulens"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "Quell- und Ziel-Cluster sind von verschiedenen Systemen"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "die Cluster sind nicht mit dieser Version von pg_rewind kompatibel"
+
+#: pg_rewind.c:703
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "Zielserver muss entweder Datenprüfsummen oder »wal_log_hints = on« verwenden"
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "Zielserver muss sauber heruntergefahren worden sein"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "Quelldatenverzeichnis muss sauber heruntergefahren worden sein"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s kB (%d%%) kopiert"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "ungültige Kontrolldatei"
+
+#: pg_rewind.c:918
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "konnte keinen gemeinsamen Anfangspunkt in den Zeitleisten von Quell- und Ziel-Cluster finden"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "Puffer für Backup-Label ist zu klein"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "unerwartete CRC in Kontrolldatei"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "unerwartete Kontrolldateigröße %d, erwartet wurde %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "WAL-Segmentgröße muss eine Zweierpotenz zwischen 1 MB und 1 GB sein, aber die Kontrolldatei gibt %d Byte an"
+msgstr[1] "WAL-Segmentgröße muss eine Zweierpotenz zwischen 1 MB und 1 GB sein, aber die Kontrolldatei gibt %d Bytes an"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid "program \"%s\" is needed by %s but was not found in the same directory as \"%s\""
+msgstr "Programm »%s« wird von %s benötigt, aber wurde nicht im selben Verzeichnis wie »%s« gefunden"
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr "Programm »%s« wurde von »%s« gefunden, aber es hatte nicht die gleiche Version wie %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "restore_command ist im Ziel-Cluster nicht gesetzt"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "führe »%s« für Zielserver aus, um Wiederherstellung abzuschließen"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "postgres im Einzelbenutzermodus im Ziel-Cluster fehlgeschlagen"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "Die Anweisung war: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "Syntaxfehler in History-Datei: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "Eine numerische Zeitleisten-ID wurde erwartet."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Eine Write-Ahead-Log-Switchpoint-Position wurde erwartet."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "ungültige Daten in History-Datei: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "Zeitleisten-IDs müssen in aufsteigender Folge sein."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "ungültige Daten in History-Datei"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "Zeitleisten-IDs müssen kleiner als die Zeitleisten-ID des Kindes sein."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "ungültiger Datensatz-Offset bei %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "Contrecord angefordert von %X/%X"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "ungültige Datensatzlänge bei %X/%X: %u erwartet, %u erhalten"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "Speicher aufgebraucht beim Versuch einen Datensatz mit Länge %u zu dekodieren"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "Datensatzlänge %u bei %X/%X ist zu lang"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "keine Contrecord-Flag bei %X/%X"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "ungültige Contrecord-Länge %u (erwartet %lld) bei %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "Contrecord fehlt bei %X/%X"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "ungültige Resource-Manager-ID %u bei %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "Datensatz mit falschem Prev-Link %X/%X bei %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "ungültige Resource-Manager-Datenprüfsumme in Datensatz bei %X/%X"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "ungültige magische Zahl %04X in Logsegment %s, Offset %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "ungültige Info-Bits %04X in Logsegment %s, Offset %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "WAL-Datei ist von einem anderen Datenbanksystem: Datenbanksystemidentifikator in WAL-Datei ist %llu, Datenbanksystemidentifikator in pg_control ist %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "WAL-Datei ist von einem anderen Datenbanksystem: falsche Segmentgröße im Seitenkopf"
+
+#: xlogreader.c:1274
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "WAL-Datei ist von einem anderen Datenbanksystem: falsche XLOG_BLCKSZ im Seitenkopf"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "unerwartete Pageaddr %X/%X in Logsegment %s, Offset %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "Zeitleisten-ID %u außer der Reihe (nach %u) in Logsegment %s, Offset %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "block_id %u außer der Reihe bei %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA gesetzt, aber keine Daten enthalten bei %X/%X"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA nicht gesetzt, aber Datenlänge ist %u bei %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE gesetzt, aber Loch Offset %u Länge %u Block-Abbild-Länge %u bei %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE nicht gesetzt, aber Loch Offset %u Länge %u bei %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_COMPRESSED gesetzt, aber Block-Abbild-Länge %u bei %X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "weder BKPIMAGE_HAS_HOLE noch BKPIMAGE_COMPRESSED gesetzt, aber Block-Abbild-Länge ist %u bei %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_REL gesetzt, aber keine vorangehende Relation bei %X/%X"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "ungültige block_id %u bei %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "Datensatz mit ungültiger Länge bei %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "konnte Backup-Block mit ID %d nicht im WAL-Eintrag finden"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "konnte Abbild bei %X/%X mit ungültigem angegebenen Block %d nicht wiederherstellen"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "konnte Abbild mit ungültigem Zustand bei %X/%X nicht wiederherstellen, Block %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid "could not restore image at %X/%X compressed with %s not supported by build, block %d"
+msgstr "konnte Abbild bei %X/%X nicht wiederherstellen, komprimiert mit %s, nicht unterstützt von dieser Installation, Block %d"
+
+#: xlogreader.c:2111
+#, c-format
+msgid "could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "konnte Abbild bei %X/%X nicht wiederherstellen, komprimiert mit unbekannter Methode, Block %d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "konnte Abbild bei %X/%X nicht dekomprimieren, Block %d"
diff --git a/src/bin/pg_rewind/po/el.po b/src/bin/pg_rewind/po/el.po
new file mode 100644
index 0000000..44cfc69
--- /dev/null
+++ b/src/bin/pg_rewind/po/el.po
@@ -0,0 +1,1016 @@
+# Greek message translation file for pg_rewind
+# Copyright (C) 2021 PostgreSQL Global Development Group
+# This file is distributed under the same license as the pg_rewind (PostgreSQL) package.
+# Georgios Kokolatos <gkokolatos@pm.me>, 2021.
+#
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL) 15\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2023-04-14 09:20+0000\n"
+"PO-Revision-Date: 2023-04-14 14:32+0200\n"
+"Last-Translator: Georgios Kokolatos <gkokolatos@pm.me>\n"
+"Language-Team: \n"
+"Language: el\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Poedit 3.2.2\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "σφάλμα: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "προειδοποίηση: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "λεπτομέρεια: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "υπόδειξη: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "έλλειψη μνήμης\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "δεν ήταν δυνατή η αντιγραφή δείκτη null (εσωτερικό σφάλμα)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "δεν ήταν δυνατή η φόρτωση της βιβλιοθήκης «%s»: κωδικός σφάλματος %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "δεν ήταν δυνατή η δημιουργία διακριτικών περιορισμού στην παρούσα πλατφόρμα: κωδικός σφάλματος %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "δεν ήταν δυνατό το άνοιγμα διακριτικού διεργασίας: κωδικός σφάλματος %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "δεν ήταν δυνατή η εκχώρηση SID: κωδικός σφάλματος %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "δεν ήταν δυνατή η δημιουργία διακριτικού διεργασίας: κωδικός σφάλματος %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "δεν ήταν δυνατή η εκκίνηση διεργασίας για την εντολή «%s»: κωδικός σφάλματος %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "δεν ήταν δυνατή η επανεκκίνηση με διακριτικό περιορισμού: κωδικός σφάλματος %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "δεν ήταν δυνατή η απόκτηση κωδικού εξόδου από την υποδιεργασία: κωδικός σφάλματος %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "δεν είναι δυνατή η χρήση restore_command μαζί με %%r placeholder"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "μη αναμενόμενο μέγεθος αρχείου για «%s»: %lld αντί για %lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "δεν ήταν δυνατό το άνοιγμα του αρχείου «%s» που έχει επαναφερθεί από την αρχειοθήκη: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "δεν ήταν δυνατή η εκτέλεση stat στο αρχείο «%s»: %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "restore_command απέτυχε: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "δεν ήταν δυνατή η επαναφορά του αρχείου «%s» από την αρχειοθήκη"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "έλλειψη μνήμης"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "δεν ήταν δυνατό το άνοιγμα του αρχείου «%s»: %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "δεν ήταν δυνατή η εγγραφή στο αρχείο «%s»: %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "δεν ήταν δυνατή η δημιουργία αρχείου «%s»: %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "δεν ήταν δυνατό το άνοιγμα του αρχείου προορισμού «%s»: %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "δεν ήταν δυνατό το κλείσιμο του αρχείου προορισμού «%s»: %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "δεν ήταν δυνατή η αναζήτηση στο αρχείο προορισμού «%s»: %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "δεν ήταν δυνατή η εγγραφή αρχείου «%s»: %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "απροσδιόριστος τύπος αρχείου για το «%s»"
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "μη έγκυρη ενέργεια (CREATE) για κανονικό αρχείο"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "δεν ήταν δυνατή η αφαίρεση του αρχείου «%s»: %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "δεν ήταν δυνατό το άνοιγμα του αρχείου «%s» για περικοπή: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "δεν ήταν δυνατή η περικοπή του αρχείου «%s» σε %u: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "δεν ήταν δυνατή η δημιουργία του καταλόγου «%s»: %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "δεν ήταν δυνατή η αφαίρεση του καταλόγου «%s»: %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "δεν ήταν δυνατή η δημιουργία του συμβολικού συνδέσμου «%s»: %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "δεν ήταν δυνατή η αφαίρεση της συμβολικής σύνδεσης «%s»: %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "δεν ήταν δυνατό το άνοιγμα αρχείου «%s» για ανάγνωση: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "δεν ήταν δυνατή η ανάγνωση του αρχείου «%s»: %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "δεν ήταν δυνατή η ανάγνωση του αρχείου «%s»: ανέγνωσε %d από %zu"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "δεν ήταν δυνατό το άνοιγμα του καταλόγου «%s»: %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "δεν ήταν δυνατή η ανάγνωση του συμβολικού συνδέσμου «%s»: %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "ο συμβολικός σύνδεσμος «%s» είναι πολύ μακρύς"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "«%s» είναι ένας συμβολικός σύνδεσμος, αλλά οι συμβολικοί σύνδεσμοι δεν υποστηρίζονται σε αυτήν την πλατφόρμα"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "δεν ήταν δυνατή η ανάγνωση του καταλόγου «%s»: %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "δεν ήταν δυνατό το κλείσιμο του καταλόγου «%s»: %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "το αρχείο «%s» δεν είναι ένα κανονικό αρχείο"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "διπλότυπο αρχείο προέλευσης «%s»"
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "μη αναμενόμενη τροποποίηση σελίδας για μη κανονικό αρχείο «%s»"
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "άγνωστος τύπος αρχείου για το «%s»"
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "το αρχείο «%s» είναι διαφορετικού τύπου στην προέλευση και τον προορισμό"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "δεν ήταν δυνατή η λήψη του αρχείου «%s»"
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "δεν ήταν δυνατή η εκκαθάριση του search_path: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "full_page_writes πρέπει να είναι ενεργοποιημένο στο διακομιστή προέλευσης"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "δεν ήταν δυνατή η προετοιμασία της δήλωσης για τη λήψη περιεχομένων αρχείου: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "σφάλμα κατά την εκτέλεση ερωτήματος (%s) στο διακομιστή προέλευσης: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "μη αναμενόμενο σύνολο αποτελεσμάτων από ερώτημα"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "σφάλμα κατά την εκτέλεση ερωτήματος (%s) στο διακομιστή προέλευσης: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "μη αναγνωρίσιμο αποτέλεσμα «%s» για την τρέχουσα θέση εισαγωγής WAL"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "δεν ήταν δυνατή η λήψη λίστας αρχείων: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "μη αναμενόμενο σύνολο αποτελεσμάτων κατά τη λήψη λίστας αρχείων"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "δεν ήταν δυνατή η αποστολή ερωτήματος: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "δεν ήταν δυνατή η ρύθμιση της σύνδεσης libpq σε λειτουργία μονής σειράς"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "μη αναμενόμενο αποτέλεσμα κατά τη λήψη απομακρυσμένων αρχείων: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "έλαβε περισσότερα τμήματα δεδομένων από όσα ζητήθηκαν"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "μη αναμενόμενο μέγεθος συνόλου αποτελεσμάτων κατά τη λήψη απομακρυσμένων αρχείων"
+
+#: libpq_source.c:515
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "μη αναμενόμενοι τύποι δεδομένων στο σύνολο αποτελεσμάτων κατά τη λήψη απομακρυσμένων αρχείων: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "μη αναμενόμενη μορφή αποτελέσματος κατά τη λήψη απομακρυσμένων αρχείων"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "μη αναμενόμενες τιμές null κατά τη λήψη απομακρυσμένων αρχείων"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "μη αναμενόμενο μήκος αποτελέσματος κατά τη λήψη απομακρυσμένων αρχείων"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "έλαβε δεδομένα για το αρχείο «%s», όταν ζητήθηκε το «%s»"
+
+#: libpq_source.c:570
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "έλαβε δεδομένα σε μετατόπιση %lld του αρχείου «%s», όταν ζητήθηκε μετατόπιση %lld"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "έλαβε περισσότερα από όσα ζήτησε για το αρχείο «%s»"
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "έλαβε μη αναμενόμενο αριθμό τμημάτων δεδομένων"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "δεν ήταν δυνατή η λήψη απομακρυσμένου αρχείου «%s»: %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "μη αναμενόμενο σύνολο αποτελεσμάτων κατά τη λήψη απομακρυσμένου αρχείου «%s»"
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "δεν ήταν δυνατό το άνοιγμα του αρχείου προέλευσης «%s»: %m"
+
+#: local_source.c:117
+#, c-format
+msgid "size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "το μέγεθος αρχείου πηγής «%s» άλλαξε σύγχρονα: αναμένονταν %d bytes, αντιγράφηκαν %d"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "δεν ήταν δυνατό το κλείσιμο του αρχείου «%s»: %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "δεν ήταν δυνατή η αναζήτηση στο αρχείο προέλευσης: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "μη αναμενόμενο EOF κατά την ανάγνωση αρχείου «%s»"
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "η μνήμη δεν επαρκεί για την εκχώρηση επεξεργαστή ανάγνωσης WAL"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "δεν ήταν δυνατή η ανάγνωση WAL εγγραφής στο %X/%X: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "δεν ήταν δυνατή η ανάγνωση WAL εγγραφής στο %X/%X"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "ο δείκτης τέλους %X/%X δεν είναι έγκυρο σημείο τέλους- αναμενόταν %X/%X"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "δεν ήταν δυνατή η εύρεση προηγούμενης WAL εγγραφής σε %X/%X: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "δεν ήταν δυνατή η εύρεση προηγούμενης WAL εγγραφής σε %X/%X"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "δεν ήταν δυνατή η αναζήτηση στο αρχείο «%s»: %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr "Η εγγραφή WAL τροποποιεί μια σχέση, αλλά ο τύπος εγγραφής δεν αναγνωρίζεται: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s επανασυγχρονίζει μία συστάδα PostgreSQL με ένα άλλο αντίγραφο της συστάδας.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"Χρήση:\n"
+" %s [ΕΠΙΛΟΓΗ]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "Επιλογές:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal χρησιμοποίησε restore_command στη ρύθμιση προορισμού για την\n"
+" ανάκτηση αρχείων WAL από αρχειοθήκες\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=DIRECTORY υπάρχον κατάλογος δεδομένων προς τροποποιήση\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=DIRECTORY κατάλογος δεδομένων προέλευσης για συγχρονισμό\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=CONNSTR διακομιστής προέλευσης για συγχρονισμό\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run τερματισμός πριν να τροποποιηθεί οτιδήποτε\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr " -N, --no-sync να μην αναμένει την ασφαλή εγγραφή αλλαγών στον δίσκο\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress εμφάνισε πληροφορίες προόδου\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf εγγραφή των ρυθμίσεων αναπαραγωγής\n"
+" (απαιτεί --source-server)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=FILENAME χρησιμοποίησε το ορισμένο αρχείο ρυθμίσεων του βασικού διακομιστή\n"
+" κατά την εκτέλεση συστάδας προορισμού\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug εγγραφή πολλών μηνύματων εντοπισμού σφαλμάτων\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr " --no-ensure-shutdown να μην διορθώνει αυτόματα ακάθαρτο τερματισμό\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version εμφάνισε πληροφορίες έκδοσης, στη συνέχεια έξοδος\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help εμφάνισε αυτό το μήνυμα βοήθειας, στη συνέχεια έξοδος\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"Υποβάλετε αναφορές σφάλματων σε <%s>.\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "%s αρχική σελίδα: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "Δοκιμάστε «%s --help» για περισσότερες πληροφορίες."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "δεν καθορίστηκε προέλευση (--source-pgdata ή --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "μόνο ένα από τα --source-pgdata ή --source-server μπορεί να καθοριστεί"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "δεν καθορίστηκε κατάλογος δεδομένων προορισμού (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "δεν καθορίστηκαν πληροφορίες διακομιστή προέλευσης (--source-server) για --write-recovery-conf"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "πάρα πολλές παράμετροι εισόδου από την γραμμή εντολών (η πρώτη είναι η «%s»)"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "δεν είναι δυνατή η εκτέλεση από «root»"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "Πρέπει να εκτελέσετε %s ως υπερχρήστης PostgreSQL."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "δεν ήταν δυνατή η ανάγνωση δικαιωμάτων του καταλόγου «%s»: %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "συνδεδεμένος στον διακομιστή"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "συστάδες προορισμού και προέλευσης βρίσκονται στην ίδια χρονογραμμή"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "οι διακομιστές αποκλίνουν στην τοποθεσία WAL %X/%X στη χρονογραμμή %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "δεν απαιτείται επαναφορά"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "επαναφορά από το τελευταίο κοινό σημείο ελέγχου στο %X/%X στη χρονογραμμή %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "ανάγνωση λίστας αρχείων προέλευσης"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "ανάγνωση λίστας αρχείων προορισμού"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "ανάγνωση WAL στον προορισμό"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "πρέπει να αντιγραφούν %lu MB (το συνολικό μέγεθος καταλόγου προέλευσης είναι %lu MB)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "συγχρονισμός καταλόγου δεδομένων προορισμού"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "Ολοκληρώθηκε!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "καμία ενέργεια δεν αποφασίστηκε για το αρχείο «%s»"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "το σύστημα προέλευσης τροποποιήθηκε κατά την εκτέλεση του pg_rewind"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "δημιουργία ετικέτας αντιγράφων ασφαλείας και ενημέρωση αρχείου ελέγχου"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "το σύστημα προέλευσης βρισκόταν σε μη αναμενόμενη κατάσταση στο τέλος της επαναφοράς"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "οι συστάδες προέλευσης και προορισμού προέρχονται από διαφορετικά συστήματα"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "η συστάδα δεν είναι συμβατή με αυτήν την έκδοση pg_rewind"
+
+#: pg_rewind.c:703
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "ο διακομιστής προορισμού πρέπει να χρησιμοποιεί είτε άθροισμα ελέγχου δεδομένων είτε «wal_log_hints = on»"
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "ο διακομιστής προορισμού πρέπει να τερματιστεί καθαρά"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "ο κατάλογος δεδομένων προέλευσης πρέπει να τερματιστεί καθαρά"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s kB (%d%%) αντιγράφηκαν"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "μη έγκυρο αρχείο ελέγχου"
+
+#: pg_rewind.c:918
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "δεν ήταν δυνατή η εύρεση κοινού προγόνου των χρονογραμμών των συστάδων προέλευσης και προορισμού"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "ενδιάμεση μνήμη ετικέτας αντιγράφων ασφαλείας πολύ μικρή"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "μη αναμενόμενο αρχείο ελέγχου CRC"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "μη αναμενόμενο μέγεθος αρχείου ελέγχου %d, αναμένεται %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "η τιμή του μεγέθους τμήματος WAL πρέπει να ανήκει σε δύναμη του δύο μεταξύ 1 MB και 1 GB, αλλά το αρχείο ελέγχου καθορίζει %d byte"
+msgstr[1] "η τιμή του μεγέθους τμήματος WAL πρέπει να ανήκει σε δύναμη του δύο μεταξύ 1 MB και 1 GB, αλλά το αρχείο ελέγχου καθορίζει %d bytes"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid "program \"%s\" is needed by %s but was not found in the same directory as \"%s\""
+msgstr "το πρόγραμμα «%s» απαιτείται από %s αλλά δεν βρέθηκε στον ίδιο κατάλογο με το «%s»"
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr "το πρόγραμμα «%s» βρέθηκε από το «%s» αλλά δεν ήταν η ίδια έκδοση με το %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "η εντολή restore_command δεν έχει οριστεί στη συστάδα προορισμού"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "εκτέλεση «%s» για την ολοκλήρωση της αποκατάστασης σφαλμάτων του διακομιστή προορισμού"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "λειτουργία μοναδικού-χρήστη postgres στο σύμπλεγμα προορισμού απέτυχε"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "Η εντολή ήταν: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "συντακτικό σφάλμα στο αρχείο ιστορικού: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "Αναμένεται αριθμητικό ID χρονογραμμής."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Αναμένεται μια θέση write-ahead log switchpoint."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "μη έγκυρα δεδομένα στο αρχείο ιστορικού: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "Τα IDs χρονογραμμής πρέπει να βρίσκονται σε αυξάνουσα σειρά."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "μη έγκυρα δεδομένα στο αρχείο ιστορικού"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "Τα ID χρονογραμμής πρέπει να είναι λιγότερα από τα ID της χρονογραμμής απογόνου."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "μη έγκυρη μετατόπιση εγγραφών σε %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "contrecord ζητείται από %X/%X"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "μη έγκυρο μήκος εγγραφής σε %X/%X: χρειαζόταν %u, έλαβε %u"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "έλλειψη μνήμης κατά την προσπάθεια αποκωδικοποίησης εγγραφής με μήκος %u"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "μήκος εγγραφής %u σε %X/%X πολύ μακρύ"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "δεν υπάρχει σημαία contrecord στο %X/%X"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "μη έγκυρο μήκος contrecord %u (αναμένεται %lld) σε %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "λείπει contrecord στο %X/%X"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "μη έγκυρο ID %u διαχειριστή πόρων στο %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "εγγραφή με εσφαλμένο prev-link %X/%X σε %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "εσφαλμένο άθροισμα ελέγχου δεδομένων διαχειριστή πόρων σε εγγραφή στο %X/%X"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "μη έγκυρος μαγικός αριθμός %04X στο τμήμα καταγραφής %s, μετατόπιση %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "μη έγκυρα info bits %04X στο τμήμα καταγραφής %s, μετατόπιση %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "WAL αρχείο προέρχεται από διαφορετικό σύστημα βάσης δεδομένων: το WAL αναγνωριστικό συστήματος βάσης δεδομένων αρχείων είναι %llu, το pg_control αναγνωριστικό συστήματος βάσης δεδομένων είναι %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "WAL αρχείο προέρχεται από διαφορετικό σύστημα βάσης δεδομένων: εσφαλμένο μέγεθος τμήματος στην κεφαλίδα σελίδας"
+
+#: xlogreader.c:1274
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "WAL αρχείο προέρχεται από διαφορετικό σύστημα βάσης δεδομένων: εσφαλμένο XLOG_BLCKSZ στην κεφαλίδα σελίδας"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "μη αναμενόμενο pageaddr %X/%X στο τμήμα καταγραφής %s, μετατόπιση %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "εκτός ακολουθίας ID χρονογραμμής %u (μετά %u) στο τμήμα καταγραφής %s, μετατόπιση %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "εκτός ακολουθίας block_id %u στο %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA έχει οριστεί, αλλά δεν περιλαμβάνονται δεδομένα σε %X/%X"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA δεν έχει οριστεί, αλλά το μήκος των δεδομένων είναι %u σε %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE έχει οριστεί, αλλά οπή με μετατόπιση %u μήκος %u μήκος μπλοκ εικόνας %u σε %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE δεν έχει οριστεί, αλλά οπή με μετατόπιση %u μήκος %u σε %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_IS_COMPRESSED έχει οριστεί, αλλά μέγεθος μπλοκ εικόνας %u σε %X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "ούτε BKPIMAGE_HAS_HOLE ούτε BKPIMAGE_IS_COMPRESSED είναι ορισμένα, αλλά το μήκος της εικόνας μπλοκ είναι %u στο %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_REL είναι ορισμένο, αλλά καμία προηγούμενη rel στο %X/%X"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "μη έγκυρο block_id %u στο %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "εγγραφή με μη έγκυρο μήκος στο %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "δεν ήταν δυνατή η εύρεση μπλοκ αντιγράφου με ID %d στην εγγραφή WAL"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "δεν ήταν δυνατή η επαναφορά εικόνας στο %X/%X με ορισμένο άκυρο μπλοκ %d"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "δεν ήταν δυνατή η επαναφορά εικόνας στο %X/%X με άκυρη κατάσταση, μπλοκ %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid "could not restore image at %X/%X compressed with %s not supported by build, block %d"
+msgstr "δεν ήταν δυνατή η επαναφορά εικόνας σε %X/%X συμπιεσμένη με %s που δεν υποστηρίζεται από την υλοποίηση, μπλοκ %d"
+
+#: xlogreader.c:2111
+#, c-format
+msgid "could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "δεν ήταν δυνατή η επαναφορά εικόνας σε %X/%X συμπιεσμένη με άγνωστη μέθοδο, μπλοκ %d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "δεν ήταν δυνατή η αποσυμπιέση εικόνας στο %X/%X, μπλοκ %d"
+
+#~ msgid "You must run %s as the PostgreSQL superuser.\n"
+#~ msgstr "Πρέπει να εκτελέσετε %s ως υπερχρήστης PostgreSQL.\n"
+
+#~ msgid "fatal: "
+#~ msgstr "κρίσιμο: "
diff --git a/src/bin/pg_rewind/po/es.po b/src/bin/pg_rewind/po/es.po
new file mode 100644
index 0000000..06923db
--- /dev/null
+++ b/src/bin/pg_rewind/po/es.po
@@ -0,0 +1,1013 @@
+# Spanish message translation file for pg_rewind
+#
+# Copyright (c) 2015-2021, PostgreSQL Global Development Group
+# This file is distributed under the same license as the PostgreSQL package.
+#
+# Álvaro Herrera <alvherre@alvh.no-ip.org>, 2015.
+# Carlos Chapi <carloswaldo@babelruins.org>, 2017, 2021.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL) 15\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2023-05-07 16:50+0000\n"
+"PO-Revision-Date: 2022-10-20 09:06+0200\n"
+"Last-Translator: Carlos Chapi <carloswaldo@babelruins.org>\n"
+"Language-Team: PgSQL-es-Ayuda <pgsql-es-ayuda@lists.postgresql.org>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 2.4.3\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "error: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "precaución: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "detalle: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "consejo: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "memoria agotada\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "no se puede duplicar un puntero nulo (error interno)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "no se pudo cargar la biblioteca «%s»: código de error %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "no se pueden crear tokens restrigidos en esta plataforma: código de error %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "no se pudo abrir el token de proceso: código de error %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "no se pudo emplazar los SIDs: código de error %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "no se pudo crear el token restringido: código de error %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "no se pudo iniciar el proceso para la orden «%s»: código de error %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "no se pudo re-ejecutar con el token restringido: código de error %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "no se pudo obtener el código de salida del subproceso»: código de error %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "no se puede usar restore_command con el marcador %%r"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "el archivo «%s» tiene tamaño inesperado: %lld en lugar de %lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "no se pudo abrir el archivo «%s» restaurado del archivo: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "no se pudo hacer stat al archivo «%s»: %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "restore_command falló: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "no se pudo recuperar el archivo «%s» del archivo"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "memoria agotada"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "no se pudo abrir el archivo «%s»: %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "no se pudo escribir a archivo «%s»: %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "no se pudo crear archivo «%s»: %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "no se pudo abrir el archivo de destino «%s»: %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "no se pudo cerrar el archivo de destino «%s»: %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "no se pudo posicionar en archivo de destino «%s»: %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "no se pudo escribir el archivo «%s»: %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "tipo de archivo no definido para «%s»"
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "acción no válida (CREATE) para archivo regular"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "no se pudo eliminar el archivo «%s»: %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "no se pudo abrir el archivo «%s» para truncarlo: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "no se pudo truncar el archivo «%s» a %u: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "no se pudo crear el directorio «%s»: %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "no se pudo eliminar el directorio «%s»: %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "no se pudo crear el link simbólico en «%s»: %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "no se pudo eliminar el enlace simbólico «%s»: %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "no se pudo abrir archivo «%s» para lectura: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "no se pudo leer el archivo «%s»: %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "no se pudo leer el archivo «%s»: leídos %d de %zu"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "no se pudo abrir el directorio «%s»: %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "no se pudo leer el enlace simbólico «%s»: %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "la ruta «%s» del enlace simbólico es demasiado larga"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "«%s» es un link simbólico, pero los links simbólicos no están soportados en esta plataforma"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "no se pudo leer el directorio «%s»: %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "no se pudo abrir el directorio «%s»: %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "el archivo de datos «%s» en el origen no es un archivo regular"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "archivo origen duplicado «%s»"
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "modificación de página inesperada para el archivo no regular «%s»"
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "tipo de archivo desconocido para «%s»"
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "el archivo «%s» tiene un tipo diferente en el origen y en el destino"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "no se pudo decidir qué hacer con el archivo «%s»"
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "no se pudo limpiar search_path: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "full_page_writes debe estar activado en el servidor de origen"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "no se pudo preparar sentencia para obtener el contenido del archivo: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "error ejecutando consulta (%s) en el servidor de origen: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "conjunto de resultados inesperados de la consulta"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "error ejecutando consulta (%s) en el servidor de origen: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "resultado «%s» no reconocido para la ubicación de inserción WAL actual"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "no se pudo obtener el listado de archivos: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "conjunto de resultados inesperado mientras se obtenía el listado de archivos"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "no se pudo enviar la consulta: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "no se pudo establecer la coneción libpq a modo «single row»"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "resultados inesperados mientras se obtenían archivos remotos: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "se recibieron más trozos de datos que los solicitados"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "tamaño del conjunto de resultados inesperado mientras se obtenían archivos remotos"
+
+#: libpq_source.c:515
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "tipos de dato inesperados en el conjunto de resultados mientras se obtenían archivos remotos: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "formato de resultados inesperado mientras se obtenían archivos remotos"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "valores nulos inesperados en el resultado mientras se obtenían archivos remotos"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "largo del resultado inesperado mientras se obtenían los archivos remotos"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "se recibieron datos para el archivo «%s», cuando se solicitó para «%s»"
+
+#: libpq_source.c:570
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "se recibieron datos en la posición %lld del archivo «%s», cuando se solicitó para la posición %lld"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "se recibió más de lo solicitado para el archivo «%s»"
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "se recibió un número inesperado de trozos de datos"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "no se pudo obtener el archivo remoto «%s»: %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "conjunto de resultados inesperado mientras se obtenía el archivo remoto «%s»"
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "no se pudo abrir el archivo de origen «%s»: %m"
+
+#: local_source.c:117
+#, c-format
+msgid "size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "el tamaño del archivo de origen «%s» cambió concurrentemente: se esperaban %d bytes, se copiaron %d"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "no se pudo cerrar el archivo «%s»: %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "no se pudo posicionar en archivo de origen: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "EOF inesperado mientras se leía el archivo «%s»"
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "memoria agotada mientras se emplazaba un procesador de lectura de WAL"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "no se pudo leer el registro WAL en %X/%X: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "no se pudo leer el registro WAL en %X/%X"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "el puntero de término %X/%X no es un punto válido; se esperaba %X/%X"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "no se pudo encontrar el registro WAL anterior en %X/%X: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "no se pudo encontrar el registro WAL anterior en %X/%X"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "no se pudo posicionar (seek) el archivo «%s»: %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr "el registro WAL modifica una relación, pero el tipo de registro no es reconocido: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s resincroniza un cluster PostgreSQL con otra copia del cluster.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"Empleo:\n"
+" %s [OPCION]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "Opciones:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal utilizar restore_command de la configuración\n"
+" de destino para obtener archivos WAL\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=DIRECTORIO directorio de datos existente a modificar\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=DIRECTORIO directorio de datos de origen a sincronizar\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=CONN servidor de origen a sincronizar\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run detener antes de modificar nada\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr " -N, --no-sync no esperar que los cambios se sincronicen a disco\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress escribir mensajes de progreso\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf escribe configuración para replicación\n"
+" (requiere --source-server)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=ARCHIVO utilizar el archivo de configuración del servidor\n"
+" principal especificado al ejecutar el clúster de destino\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug escribir muchos mensajes de depuración\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr ""
+" --no-ensure-shutdown no corregir automáticamente un apagado\n"
+" no-limpio\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version mostrar información de versión y salir\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help mostrar esta ayuda y salir\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"Reporte errores a <%s>.\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "Sitio web de %s: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "Pruebe «%s --help» para mayor información."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "no se especificó origen (--source-pgdata o --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "sólo uno de --source-pgdata o --source-server puede ser especificado"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "no se especificó directorio de datos de destino (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "no se especificó información de servidor de origen (--source-server) para --write-recovery-conf"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "demasiados argumentos en la línea de órdenes (el primero es «%s»)"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "no puede ser ejecutado por «root»"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "Debe ejecutar %s con el superusuario de PostgreSQL."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "no se pudo obtener los permisos del directorio «%s»: %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "conectado al servidor"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "el cluster de origen y destino están en el mismo timeline"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "servidores divergieron en la posición de WAL %X/%X en el timeline %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "no se requiere rebobinar"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "rebobinando desde el último checkpoint común en %X/%X en el timeline %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "leyendo la lista de archivos de origen"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "leyendo la lista de archivos de destino"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "leyendo WAL en destino"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "se necesitan copiar %lu MB (tamaño total de directorio de origen es %lu MB)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "sincronizando directorio de datos de destino"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "¡Listo!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "no se decidió una acción para el archivo «%s»"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "el sistema origen fue modificado mientras pg_rewind estaba en ejecución"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "creando etiqueta de respaldo y actualizando archivo de control"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "el sistema origen estaba en un estado inesperado al final del rebobinado"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "clusters de origen y destino son de sistemas diferentes"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "los clusters no son compatibles con esta versión de pg_rewind"
+
+#: pg_rewind.c:703
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "el servidor de destino necesita tener sumas de verificación de datos o «wal_log_hints» activados"
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "el directorio de destino debe estar apagado limpiamente"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "el directorio de origen debe estar apagado limpiamente"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s kB (%d%%) copiados"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "archivo de control no válido"
+
+#: pg_rewind.c:918
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "no se pudo encontrar un ancestro común en el timeline de los clusters de origen y destino"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "el búfer del backup label es demasiado pequeño"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "CRC de archivo de control inesperado"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "tamaño del archivo de control %d inesperado, se esperaba %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "El tamaño del segmento de WAL debe ser una potencia de dos entre 1 MB y 1 GB, pero el archivo de control especifica %d byte"
+msgstr[1] "El tamaño del segmento de WAL debe ser una potencia de dos entre 1 MB y 1 GB, pero el archivo de control especifica %d bytes"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid "program \"%s\" is needed by %s but was not found in the same directory as \"%s\""
+msgstr "el programa «%s» es requerido por %s, pero no se encontró en el mismo directorio que «%s»"
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr "el programa «%s» fue encontrado por «%s» pero no es de la misma versión que %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "restore_command no está definido en el clúster de destino"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "ejecutando «%s» en el servidor de destino para completar la recuperación de caídas"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "el modo «single-user» en el servidor de destino falló"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "La orden era: % s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "error de sintaxis en archivo de historia: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "Se esperaba un ID numérico de timeline."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Se esperaba una ubicación de punto de cambio del «write-ahead log»."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "datos no válidos en archivo de historia: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "IDs de timeline deben ser una secuencia creciente."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "datos no válidos en archivo de historia"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "IDs de timeline deben ser menores que el ID de timeline del hijo."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "posición de registro no válida en %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "contrecord solicitado por %X/%X"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "largo de registro no válido en %X/%X: se esperaba %u, se obtuvo %u"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "memoria agotada mientras se intentaba decodificar un registro de largo %u"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "largo de registro %u en %X/%X demasiado largo"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "no hay bandera de contrecord en %X/%X"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "largo de contrecord %u no válido (se esperaba %lld) en %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "falta un contrecord en %X/%X"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "ID de gestor de recursos %u no válido en %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "registro con prev-link %X/%X incorrecto en %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "suma de verificación de los datos del gestor de recursos incorrecta en el registro en %X/%X"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "número mágico %04X no válido en archivo %s, posición %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "info bits %04X no válidos en archivo %s, posición %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "archivo WAL es de un sistema de bases de datos distinto: identificador de sistema en archivo WAL es %llu, identificador en pg_control es %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "archivo WAL es de un sistema de bases de datos distinto: tamaño de segmento incorrecto en cabecera de paǵina"
+
+#: xlogreader.c:1274
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "archivo WAL es de un sistema de bases de datos distinto: XLOG_BLCKSZ incorrecto en cabecera de paǵina"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "pageaddr %X/%X inesperado en archivo %s, posición %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "ID de timeline %u fuera de secuencia (después de %u) en archivo %s, posición %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "block_id %u fuera de orden en %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA está definido, pero no hay datos en %X/%X"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA no está definido, pero el largo de los datos es %u en %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE está definido, pero posición del agujero es %u largo %u largo de imagen %u en %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE no está definido, pero posición del agujero es %u largo %u en %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_COMPRESSED definido, pero largo de imagen de bloque es %u en %X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "ni BKPIMAGE_HAS_HOLE ni BKPIMAGE_COMPRESSED están definidos, pero el largo de imagen de bloque es %u en %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_REL está definido, pero no hay «rel» anterior en %X/%X "
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "block_id %u no válido en %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "registro con largo no válido en %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "no se pudo localizar un bloque de respaldo con ID %d en el registro WAL"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "no se pudo restaurar la imagen en %X/%X con bloque especificado %d no válido"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "no se pudo restaurar la imagen en %X/%X con estado no válido, bloque %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid "could not restore image at %X/%X compressed with %s not supported by build, block %d"
+msgstr "no se pudo restaurar la imagen en %X/%X comprimida con %s que no está soportado por esta instalación, bloque %d"
+
+#: xlogreader.c:2111
+#, c-format
+msgid "could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "no se pudo restaurar la imagen en %X/%X comprimida con un método desconocido, bloque %d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "no se pudo descomprimir la imagen en %X/%X, bloque %d"
diff --git a/src/bin/pg_rewind/po/fr.po b/src/bin/pg_rewind/po/fr.po
new file mode 100644
index 0000000..d931607
--- /dev/null
+++ b/src/bin/pg_rewind/po/fr.po
@@ -0,0 +1,1300 @@
+# LANGUAGE message translation file for pg_rewind
+# Copyright (C) 2016-2022 PostgreSQL Global Development Group
+# This file is distributed under the same license as the pg_rewind (PostgreSQL) package.
+#
+# Use these quotes: « %s »
+#
+# Guillaume Lelarge <guillaume@lelarge.info>, 2016-2022.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PostgreSQL 15\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2022-09-26 08:20+0000\n"
+"PO-Revision-Date: 2022-09-26 14:16+0200\n"
+"Last-Translator: Guillaume Lelarge <guillaume@lelarge.info>\n"
+"Language-Team: French <guillaume@lelarge.info>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"X-Generator: Poedit 3.1.1\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "erreur : "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "attention : "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "détail : "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "astuce : "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "mémoire épuisée\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "ne peut pas dupliquer un pointeur nul (erreur interne)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "n'a pas pu charger la bibliothèque « %s » : code d'erreur %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "ne peut pas créer les jetons restreints sur cette plateforme : code d'erreur %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "n'a pas pu ouvrir le jeton du processus : code d'erreur %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "n'a pas pu allouer les SID : code d'erreur %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "n'a pas pu créer le jeton restreint : code d'erreur %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "n'a pas pu démarrer le processus pour la commande « %s » : code d'erreur %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "n'a pas pu ré-exécuter le jeton restreint : code d'erreur %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "n'a pas pu récupérer le code de statut du sous-processus : code d'erreur %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "ne peut pas utiliser restore_command avec le joker %%r"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "taille de fichier inattendu pour « %s » : %lld au lieu de %lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "n'a pas pu ouvrir le fichier « %s » à partir de l'archive : %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "n'a pas pu tester le fichier « %s » : %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "échec de la restore_command : %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "n'a pas pu restaurer le fichier « %s » à partir de l'archive"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "mémoire épuisée"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "n'a pas pu ouvrir le fichier « %s » : %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "n'a pas pu écrire dans le fichier « %s » : %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "n'a pas pu créer le fichier « %s » : %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "n'a pas pu ouvrir le fichier cible « %s » : %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "n'a pas pu fermer le fichier cible « %s » : %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "n'a pas pu chercher dans le fichier cible « %s » : %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "impossible d'écrire le fichier « %s » : %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "type de fichier non défini pour « %s »"
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "action (CREATE) invalide pour le fichier régulier"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "n'a pas pu supprimer le fichier « %s » : %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "n'a pas pu ouvrir le fichier « %s » pour le troncage : %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "n'a pas pu tronquer le fichier « %s » en %u : %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "n'a pas pu créer le répertoire « %s » : %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "n'a pas pu supprimer le répertoire « %s » : %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "n'a pas pu créer le lien symbolique à « %s » : %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "n'a pas pu supprimer le lien symbolique « %s » : %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "n'a pas pu ouvrir le fichier « %s » pour une lecture : %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "n'a pas pu lire le fichier « %s » : %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "n'a pas pu lire le fichier « %s » : a lu %d sur %zu"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "n'a pas pu ouvrir le répertoire « %s » : %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "n'a pas pu lire le lien symbolique « %s » : %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "la cible du lien symbolique « %s » est trop longue"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "« %s » est un lien symbolique mais les liens symboliques ne sont pas supportés sur cette plateforme"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "n'a pas pu lire le répertoire « %s » : %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "n'a pas pu fermer le répertoire « %s » : %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "le fichier de données « %s » en source n'est pas un fichier standard"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "fichier source « %s » dupliqué"
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "modification inattendue de page pour le fichier non standard « %s »"
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "type de fichier inconnu pour « %s »"
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "le fichier « %s » a un type différent pour la source et la cible"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "n'a pas pu décider que faire avec le fichier « %s » : %m"
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "n'a pas pu effacer search_path : %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "full_page_writes doit être activé sur le serveur source"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "n'a pas pu préparer l'instruction pour récupérer le contenu du fichier : %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "erreur lors de l'exécution de la requête (%s) sur le serveur source : %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "ensemble de résultats inattendu provenant de la requête"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "erreur lors de l'exécution de la requête (%s) dans le serveur source : %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "résultat non reconnu « %s » pour l'emplacement d'insertion actuel dans les WAL"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "n'a pas pu récupérer la liste des fichiers : %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "ensemble de résultats inattendu lors de la récupération de la liste des fichiers"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "n'a pas pu envoyer la requête : %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "n'a pas pu configurer la connexion libpq en mode ligne seule"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "résultat inattendu lors de la récupération des fichiers cibles : %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "a reçu plus de morceaux de données que demandé"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "taille inattendue de l'ensemble de résultats lors de la récupération des fichiers distants"
+
+#: libpq_source.c:515
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "types de données inattendus dans l'ensemble de résultats lors de la récupération des fichiers distants : %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "format de résultat inattendu lors de la récupération des fichiers distants"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "valeurs NULL inattendues dans le résultat lors de la récupération des fichiers distants"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "longueur de résultats inattendu lors de la récupération des fichiers distants"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "a reçu des données du fichier « %s » alors que « %s » était demandé"
+
+#: libpq_source.c:570
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "a reçu des données au décalage %lld du fichier « %s » alors que le décalage %lld était demandé"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "a reçu plus que demandé pour le fichier « %s »"
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "nombre de morceaux de données reçus inattendu"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "n'a pas pu récupérer le fichier distant « %s » : %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "ensemble de résultats inattendu lors de la récupération du fichier distant « %s »"
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "n'a pas pu ouvrir le fichier source « %s » : %m"
+
+#: local_source.c:117
+#, c-format
+msgid "size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "la taille du fichier source « %s » a changé : %d octets attendus, %d copiés"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "n'a pas pu fermer le fichier « %s » : %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "n'a pas pu chercher dans le fichier source : %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "EOF inattendu lors de la lecture du fichier « %s »"
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "manque mémoire lors de l'allocation d'un processeur de lecture de journaux de transactions"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "n'a pas pu lire l'enregistrement WAL précédent à %X/%X : %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "n'a pas pu lire l'enregistrement WAL précédent à %X/%X"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "le pointeur de fin %X/%X n'est pas un pointeur de fin valide ; %X/%X attendu"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "n'a pas pu trouver l'enregistrement WAL précédent à %X/%X : %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "n'a pas pu trouver l'enregistrement WAL précédent à %X/%X"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "n'a pas pu parcourir le fichier « %s » : %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr "l'enregistrement WAL modifie une relation mais le type d'enregistrement n'est pas reconnu : lsn : %X/%X, rmid : %d, rmgr : %s, info : %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s resynchronise une instance PostgreSQL avec une autre copie de\n"
+"l'instance.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"Usage :\n"
+" %s [OPTION]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "Options :\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal utilise restore_command pour la configuration\n"
+" cible de récupération des fichiers WAL des\n"
+" archives\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=RÉPERTOIRE répertoire de données existant à modifier\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=RÉPERTOIRE répertoire des données source\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=CHAÎNE serveur source pour la synchronisation\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run arrête avant de modifier quoi que ce soit\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr ""
+" -N, --nosync n'attend pas que les modifications soient\n"
+" proprement écrites sur disque\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress écrit les messages de progression\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf écrit la configuration pour la réplication\n"
+" (requiert --source-server)\n"
+"\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=NOMFICHIER utilise le fichier de configuration indiqué\n"
+" du serveur principal lors de l'exécution de\n"
+" l'instance cible\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug écrit beaucoup de messages de débogage\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr ""
+" --no-ensure-shutdown ne corrige pas automatiquement l'arrêt non\n"
+" propre\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version affiche la version, puis quitte\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help affiche cette aide, puis quitte\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"Rapporter les bogues à <%s>.\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "Page d'accueil de %s : <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "Essayez « %s --help » pour plus d'informations."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "aucune source indiquée (--source-pgdata ou --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "une seule des options --source-pgdata et --source-server peut être indiquée"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "aucun répertoire de données cible indiqué (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "aucune information sur le serveur source (--source-server) indiquée pour --write-recovery-conf"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "trop d'arguments en ligne de commande (le premier étant « %s »)"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "ne peut pas être exécuté par « root »"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "Vous devez exécuter %s en tant que super-utilisateur PostgreSQL."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "n'a pas pu lire les droits du répertoire « %s » : %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "connecté au serveur"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "les instances source et cible sont sur la même ligne de temps"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "les serveurs ont divergé à la position %X/%X des WAL sur la timeline %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "pas de retour en arrière requis"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "retour en arrière depuis le dernier checkpoint commun à %X/%X sur la ligne de temps %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "lecture de la liste des fichiers sources"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "lecture de la liste des fichiers cibles"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "lecture du WAL dans la cible"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "a besoin de copier %lu Mo (la taille totale du répertoire source est %lu Mo)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "synchronisation du répertoire des données cible"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "Terminé !"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "aucune action décidée pour le fichier « %s »"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "le système source a été modifié alors que pg_rewind était en cours d'exécution"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "création du fichier backup_label et mise à jour du fichier contrôle"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "le système source était dans un état inattendu en fin de rewind"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "les instances source et cible proviennent de systèmes différents"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "les instances ne sont pas compatibles avec cette version de pg_rewind"
+
+#: pg_rewind.c:703
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "le serveur cible doit soit utiliser les sommes de contrôle sur les données soit avoir wal_log_hints configuré à on"
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "le serveur cible doit être arrêté proprement"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "le répertoire de données source doit être arrêté proprement"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s Ko (%d%%) copiés"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "fichier de contrôle invalide"
+
+#: pg_rewind.c:918
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "n'a pas pu trouver l'ancêtre commun des lignes de temps des instances source et cible"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "tampon du label de sauvegarde trop petit"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "CRC inattendu pour le fichier de contrôle"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "taille %d inattendue du fichier de contrôle, %d attendu"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "La taille du segment WAL doit être une puissance de deux comprise entre 1 Mo et 1 Go, mais le fichier de contrôle indique %d octet"
+msgstr[1] "La taille du segment WAL doit être une puissance de deux comprise entre 1 Mo et 1 Go, mais le fichier de contrôle indique %d octets"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid "program \"%s\" is needed by %s but was not found in the same directory as \"%s\""
+msgstr "le programme « %s » est nécessaire pour %s, mais n'a pas été trouvé dans le même répertoire que « %s »"
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr "le programme « %s » a été trouvé par « %s » mais n'est pas de la même version que %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "restore_command n'est pas configuré sur l'instance cible"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "exécution de « %s » pour terminer la restauration après crash du serveur cible"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "le mot simple-utilisateur de postgres a échoué pour l'instance cible"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "La commande était : %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "erreur de syntaxe dans le fichier historique : %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "Attendait un identifiant timeline numérique."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Attendait un emplacement de bascule de journal de transactions."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "données invalides dans le fichier historique : %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "Les identifiants timeline doivent être en ordre croissant."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "données invalides dans le fichier historique"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr ""
+"Les identifiants timeline doivent être plus petits que les enfants des\n"
+"identifiants timeline."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "décalage invalide de l'enregistrement %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "« contrecord » est requis par %X/%X"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "longueur invalide de l'enregistrement à %X/%X : voulait %u, a eu %u"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "manque mémoire lors de la tentative de décodage d'un enregistrement de longueur %u"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "longueur trop importante de l'enregistrement %u à %X/%X"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "il n'existe pas de drapeau contrecord à %X/%X"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "longueur %u invalide du contrecord (%lld attendu) à %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "contrecord manquant à %X/%X"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "identifiant du gestionnaire de ressources invalide %u à %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "enregistrement avec prev-link %X/%X incorrect à %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr ""
+"somme de contrôle des données du gestionnaire de ressources incorrecte à\n"
+"l'enregistrement %X/%X"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "numéro magique invalide %04X dans le segment %s, décalage %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "bits d'information %04X invalides dans le segment %s, décalage %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "Le fichier WAL provient d'une instance différente : l'identifiant système de la base dans le fichier WAL est %llu, alors que l'identifiant système de la base dans pg_control est %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "Le fichier WAL provient d'une instance différente : taille invalide du segment dans l'en-tête de page"
+
+#: xlogreader.c:1274
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "Le fichier WAL provient d'une instance différente : XLOG_BLCKSZ incorrect dans l'en-tête de page"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "pageaddr %X/%X inattendue dans le journal de transactions %s, segment %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "identifiant timeline %u hors de la séquence (après %u) dans le segment %s, décalage %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "block_id %u désordonné à %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA configuré, mais aucune donnée inclus à %X/%X"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA non configuré, mais la longueur des données est %u à %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE activé, mais décalage trou %u longueur %u longueur image bloc %u à %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE désactivé, mais décalage trou %u longueur %u à %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_COMPRESSED configuré, mais la longueur de l'image du bloc est %u à %X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "ni BKPIMAGE_HAS_HOLE ni BKPIMAGE_COMPRESSED configuré, mais la longueur de l'image du bloc est %u à %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_REL configuré, mais pas de relation précédente à %X/%X"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "block_id %u invalide à %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "enregistrement de longueur invalide à %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "n'a pas pu localiser le bloc de sauvegarde d'ID %d dans l'enregistrement WAL"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "n'a pas pu restaurer l'image à %X/%X avec le bloc invalide %d indiqué"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "n'a pas pu restaurer l'image à %X/%X avec un état invalide, bloc %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid "could not restore image at %X/%X compressed with %s not supported by build, block %d"
+msgstr "n'a pas pu restaurer l'image à %X/%X compressé avec %s, qui est non supporté par le serveur, bloc %d"
+
+#: xlogreader.c:2111
+#, c-format
+msgid "could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "n'a pas pu restaurer l'image à %X/%X compressé avec une méthode inconnue, bloc %d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "n'a pas pu décompresser l'image à %X/%X, bloc %d"
+
+#~ msgid ""
+#~ "\n"
+#~ "Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Rapporter les bogues à <pgsql-bugs@lists.postgresql.org>.\n"
+
+#~ msgid " block %u\n"
+#~ msgstr " bloc %u\n"
+
+#~ msgid "\"%s\" is not a directory"
+#~ msgstr "« %s » n'est pas un répertoire"
+
+#~ msgid "\"%s\" is not a regular file"
+#~ msgstr "« %s » n'est pas un fichier standard"
+
+#~ msgid "\"%s\" is not a symbolic link"
+#~ msgstr "« %s » n'est pas un lien symbolique"
+
+#~ msgid "%d: %X/%X - %X/%X\n"
+#~ msgstr "%d : %X/%X - %X/%X\n"
+
+#~ msgid "%s (%s)\n"
+#~ msgstr "%s (%s)\n"
+
+#~ msgid "%s: WARNING: cannot create restricted tokens on this platform\n"
+#~ msgstr "%s : ATTENTION : ne peut pas créer les jetons restreints sur cette plateforme\n"
+
+#~ msgid "%s: could not allocate SIDs: error code %lu\n"
+#~ msgstr "%s : n'a pas pu allouer les SID : code d'erreur %lu\n"
+
+#~ msgid "%s: could not create restricted token: error code %lu\n"
+#~ msgstr "%s : n'a pas pu créer le jeton restreint : code d'erreur %lu\n"
+
+#~ msgid "%s: could not get exit code from subprocess: error code %lu\n"
+#~ msgstr "%s : n'a pas pu récupérer le code de statut du sous-processus : code d'erreur %lu\n"
+
+#~ msgid "%s: could not open process token: error code %lu\n"
+#~ msgstr "%s : n'a pas pu ouvrir le jeton du processus : code d'erreur %lu\n"
+
+#~ msgid "%s: could not re-execute with restricted token: error code %lu\n"
+#~ msgstr "%s : n'a pas pu ré-exécuter le jeton restreint : code d'erreur %lu\n"
+
+#~ msgid "%s: could not read permissions of directory \"%s\": %s\n"
+#~ msgstr "%s : n'a pas pu lire les droits sur le répertoire « %s » : %s\n"
+
+#~ msgid "%s: could not start process for command \"%s\": error code %lu\n"
+#~ msgstr "%s : n'a pas pu démarrer le processus pour la commande « %s » : code d'erreur %lu\n"
+
+#~ msgid "%s: too many command-line arguments (first is \"%s\")\n"
+#~ msgstr "%s : trop d'arguments en ligne de commande (le premier étant « %s »)\n"
+
+#~ msgid "Expected a numeric timeline ID.\n"
+#~ msgstr "Attendait un identifiant numérique de ligne de temps.\n"
+
+#~ msgid "Expected a write-ahead log switchpoint location.\n"
+#~ msgstr "Attendait un emplacement de bascule de journal de transactions.\n"
+
+#~ msgid "Failure, exiting\n"
+#~ msgstr "Échec, sortie\n"
+
+#~ msgid "Source timeline history:\n"
+#~ msgstr "Historique de la ligne de temps source :\n"
+
+#~ msgid "Target timeline history:\n"
+#~ msgstr "Historique de la ligne de temps cible :\n"
+
+#~ msgid ""
+#~ "The program \"%s\" is needed by %s but was\n"
+#~ "not found in the same directory as \"%s\".\n"
+#~ "Check your installation."
+#~ msgstr ""
+#~ "Le programme « %s » est nécessaire pour %s, mais n'a pas été trouvé\n"
+#~ "dans le même répertoire que « %s ».\n"
+#~ "Vérifiez votre installation."
+
+#~ msgid ""
+#~ "The program \"%s\" was found by \"%s\" but was\n"
+#~ "not the same version as %s.\n"
+#~ "Check your installation."
+#~ msgstr ""
+#~ "Le programme « %s » a été trouvé par « %s » mais n'était pas de la même version\n"
+#~ "que %s.\n"
+#~ "Vérifiez votre installation."
+
+#~ msgid ""
+#~ "The program \"initdb\" is needed by %s but was\n"
+#~ "not found in the same directory as \"%s\".\n"
+#~ "Check your installation.\n"
+#~ msgstr ""
+#~ "Le programme « initdb » est nécessaire pour %s, mais n'a pas été trouvé\n"
+#~ "dans le même répertoire que « %s ».\n"
+#~ "Vérifiez votre installation.\n"
+
+#~ msgid ""
+#~ "The program \"initdb\" was found by \"%s\"\n"
+#~ "but was not the same version as %s.\n"
+#~ "Check your installation.\n"
+#~ msgstr ""
+#~ "Le programme « initdb » a été trouvé par « %s », mais n'est pas de la même version\n"
+#~ "que %s.\n"
+#~ "Vérifiez votre installation.\n"
+
+#~ msgid ""
+#~ "The program \"postgres\" is needed by %s but was not found in the\n"
+#~ "same directory as \"%s\".\n"
+#~ "Check your installation."
+#~ msgstr ""
+#~ "Le programme « postgres » est nécessaire à %s mais n'a pas été trouvé dans\n"
+#~ "le même répertoire que « %s ».\n"
+#~ "Vérifiez votre installation."
+
+#~ msgid ""
+#~ "The program \"postgres\" was found by \"%s\"\n"
+#~ "but was not the same version as %s.\n"
+#~ "Check your installation."
+#~ msgstr ""
+#~ "Le programme « postgres » a été trouvé par « %s » mais n'est pas de la même\n"
+#~ "version que « %s ».\n"
+#~ "Vérifiez votre installation."
+
+#~ msgid "Timeline IDs must be in increasing sequence.\n"
+#~ msgstr "Les identifiants de ligne de temps doivent être dans une séquence croissante.\n"
+
+#~ msgid "Timeline IDs must be less than child timeline's ID.\n"
+#~ msgstr "Les identifiants de ligne de temps doivent être inférieurs à l'identifiant de la ligne de temps enfant.\n"
+
+#, c-format
+#~ msgid "Try \"%s --help\" for more information.\n"
+#~ msgstr "Essayez « %s --help » pour plus d'informations.\n"
+
+#~ msgid "WAL file is from different database system: incorrect XLOG_SEG_SIZE in page header"
+#~ msgstr "le fichier WAL provient d'un système différent : XLOG_SEG_SIZE invalide dans l'en-tête de page"
+
+#~ msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte\n"
+#~ msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes\n"
+#~ msgstr[0] "La taille du segment WAL doit être une puissance de deux comprise entre 1 Mo et 1 Go, mais le fichier de contrôle indique %d octet\n"
+#~ msgstr[1] "La taille du segment WAL doit être une puissance de deux comprise entre 1 Mo et 1 Go, mais le fichier de contrôle indique %d octets\n"
+
+#, c-format
+#~ msgid "You must run %s as the PostgreSQL superuser.\n"
+#~ msgstr "Vous devez exécuter %s en tant que super-utilisateur PostgreSQL.\n"
+
+#~ msgid "could not close directory \"%s\": %s\n"
+#~ msgstr "n'a pas pu fermer le répertoire « %s » : %s\n"
+
+#~ msgid "could not close file \"%s\": %s\n"
+#~ msgstr "n'a pas pu fermer le fichier « %s » : %s\n"
+
+#~ msgid "could not connect to server: %s"
+#~ msgstr "n'a pas pu se connecter au serveur : %s"
+
+#~ msgid "could not create directory \"%s\": %s\n"
+#~ msgstr "n'a pas pu créer le répertoire « %s » : %s\n"
+
+#~ msgid "could not create temporary table: %s"
+#~ msgstr "n'a pas pu créer la table temporaire : %s"
+
+#~ msgid "could not open directory \"%s\": %s\n"
+#~ msgstr "n'a pas pu ouvrir le répertoire « %s » : %s\n"
+
+#~ msgid "could not open file \"%s\" for reading: %s\n"
+#~ msgstr "n'a pas pu ouvrir le fichier « %s » pour une lecture : %s\n"
+
+#~ msgid "could not open file \"%s\": %s\n"
+#~ msgstr "n'a pas pu ouvrir le fichier « %s » : %s\n"
+
+#~ msgid "could not read directory \"%s\": %s\n"
+#~ msgstr "n'a pas pu lire le répertoire « %s » : %s\n"
+
+#~ msgid "could not read file \"%s\": %s\n"
+#~ msgstr "n'a pas pu lire le fichier « %s » : %s\n"
+
+#~ msgid "could not read from file \"%s\": %s\n"
+#~ msgstr "n'a pas pu lire le fichier « %s » : %s\n"
+
+#~ msgid "could not read symbolic link \"%s\": %s\n"
+#~ msgstr "n'a pas pu lire le lien symbolique « %s » : %s\n"
+
+#~ msgid "could not remove directory \"%s\": %s\n"
+#~ msgstr "n'a pas pu supprimer le répertoire « %s » : %s\n"
+
+#~ msgid "could not remove file \"%s\": %s\n"
+#~ msgstr "n'a pas pu supprimer le fichier « %s » : %s\n"
+
+#~ msgid "could not remove symbolic link \"%s\": %s\n"
+#~ msgstr "n'a pas pu supprimer le lien symbolique « %s » : %s\n"
+
+#~ msgid "could not seek in file \"%s\": %s\n"
+#~ msgstr "n'a pas pu chercher dans le fichier « %s » : %s\n"
+
+#~ msgid "could not send COPY data: %s"
+#~ msgstr "n'a pas pu envoyer les données COPY : %s"
+
+#~ msgid "could not send end-of-COPY: %s"
+#~ msgstr "n'a pas pu envoyer end-of-COPY : %s"
+
+#~ msgid "could not send file list: %s"
+#~ msgstr "n'a pas pu envoyer la liste de fichiers : %s"
+
+#~ msgid "could not set up connection context: %s"
+#~ msgstr "n'a pas pu initialiser le contexte de connexion : « %s »"
+
+#~ msgid "could not stat file \"%s\": %s\n"
+#~ msgstr "n'a pas pu tester le fichier « %s » : %s\n"
+
+#~ msgid "could not truncate file \"%s\" to %u: %s\n"
+#~ msgstr "n'a pas pu tronquer le fichier « %s » à %u : %s\n"
+
+#~ msgid "could not write file \"%s\": %s\n"
+#~ msgstr "n'a pas pu écrire le fichier « %s » : %s\n"
+
+#~ msgid "entry \"%s\" excluded from source file list\n"
+#~ msgstr "enregistrement « %s » exclus de la liste des fichiers sources\n"
+
+#~ msgid "entry \"%s\" excluded from target file list\n"
+#~ msgstr "enregistrement « %s » exclus de la liste des fichiers cibles\n"
+
+#, c-format
+#~ msgid "failed to locate backup block with ID %d in WAL record"
+#~ msgstr "échec de localisation du bloc de sauvegarde d'ID %d dans l'enregistrement WAL"
+
+#, c-format
+#~ msgid "fatal: "
+#~ msgstr "fatal : "
+
+#~ msgid "fetched file \"%s\", length %d\n"
+#~ msgstr "fichier récupéré « %s », longueur %d\n"
+
+#~ msgid "getting file chunks\n"
+#~ msgstr "récupération des parties de fichier\n"
+
+#, c-format
+#~ msgid "image at %X/%X compressed with %s not supported by build, block %d"
+#~ msgstr "image à %X/%X compressé avec %s, non supporté, bloc %d"
+
+#, c-format
+#~ msgid "image at %X/%X compressed with unknown method, block %d"
+#~ msgstr "image à %X/%X compressé avec une méthode inconnue, bloc %d"
+
+#, c-format
+#~ msgid "invalid compressed image at %X/%X, block %d"
+#~ msgstr "image compressée invalide à %X/%X, bloc %d"
+
+#~ msgid "invalid contrecord length %u at %X/%X reading %X/%X, expected %u"
+#~ msgstr "longueur %u invalide du contrecord à %X/%X en lisant %X/%X, attendait %u"
+
+#~ msgid "invalid data in history file: %s\n"
+#~ msgstr "données invalides dans le fichier historique : %s\n"
+
+#~ msgid "received data at offset "
+#~ msgstr "a reçu des données au décalage "
+
+#~ msgid "received null value for chunk for file \"%s\", file has been deleted\n"
+#~ msgstr "a reçu une valeur NULL pour une partie du fichier « %s », le fichier a été supprimé\n"
+
+#~ msgid "source file list is empty"
+#~ msgstr "la liste de fichiers sources est vide"
+
+#~ msgid "source server must not be in recovery mode"
+#~ msgstr "le serveur source ne doit pas être en mode restauration"
+
+#~ msgid "symbolic link \"%s\" target is too long\n"
+#~ msgstr "la cible du lien symbolique « %s » est trop long\n"
+
+#~ msgid "sync of target directory failed\n"
+#~ msgstr "échec de la synchronisation du répertoire cible\n"
+
+#~ msgid "syntax error in history file: %s\n"
+#~ msgstr "erreur de syntaxe dans le fichier historique : %s\n"
+
+#~ msgid "there is no contrecord flag at %X/%X reading %X/%X"
+#~ msgstr "il n'existe pas de drapeau contrecord à %X/%X en lisant %X/%X"
+
+#~ msgid "unexpected result while sending file list: %s"
+#~ msgstr "résultat inattendu lors de l'envoi de la liste de fichiers : %s"
diff --git a/src/bin/pg_rewind/po/it.po b/src/bin/pg_rewind/po/it.po
new file mode 100644
index 0000000..b0d4190
--- /dev/null
+++ b/src/bin/pg_rewind/po/it.po
@@ -0,0 +1,1190 @@
+#
+# pg_rewind.po
+# Italian message translation file for pg_rewind
+#
+# For development and bug report please use:
+# https://github.com/dvarrazzo/postgresql-it
+#
+# Copyright (C) 2012-2017 PostgreSQL Global Development Group
+# Copyright (C) 2010, Associazione Culturale ITPUG
+#
+# Daniele Varrazzo <daniele.varrazzo@gmail.com>, 2012-2017.
+#
+# This file is distributed under the same license as the PostgreSQL package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL) 11\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2022-09-26 08:20+0000\n"
+"PO-Revision-Date: 2022-10-05 13:58+0200\n"
+"Last-Translator: Domenico Sgarbossa <sgarbossa.domenico@gmail.com>\n"
+"Language-Team: https://github.com/dvarrazzo/postgresql-it\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Poedit-SourceCharset: utf-8\n"
+"X-Generator: Poedit 2.3\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "errore: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "avvertimento: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "dettaglio: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "suggerimento: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "memoria esaurita\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "impossibile duplicare il puntatore nullo (errore interno)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "impossibile caricare la libreria \"%s\": codice di errore %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "impossibile creare token con restrizioni su questa piattaforma: codice di errore %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "impossibile aprire il token di processo: codice di errore %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "impossibile allocare i SID: codice di errore %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "impossibile creare token limitato: codice di errore %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "impossibile avviare il processo per il comando \"%s\": codice di errore %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "impossibile rieseguire con token limitato: codice di errore %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "impossibile ottenere il codice di uscita dal processo secondario: codice di errore %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "impossibile utilizzare restore_command con %%r segnaposto"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "dimensione file imprevista per \"%s\": %lld invece di %lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "impossibile aprire il file \"%s\" ripristinato dall'archivio: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "non è stato possibile ottenere informazioni sul file \"%s\": %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "restore_command non riuscito: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "impossibile ripristinare il file \"%s\" dall'archivio"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "memoria esaurita"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "apertura del file \"%s\" fallita: %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "scrittura nel file \"%s\" fallita: %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "creazione del file \"%s\" fallita: %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "impossibile aprire il file di destinazione \"%s\": %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "impossibile chiudere il file di destinazione \"%s\": %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "impossibile cercare nel file di destinazione \"%s\": %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "scrittura nel file \"%s\" fallita: %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "tipo di file non definito per \"%s\""
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "azione non valida (CREA) per il file normale"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "rimozione del file \"%s\" fallita: %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "impossibile aprire il file \"%s\" per il troncamento: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "troncamento del file \"%s\" a %u fallito: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "creazione della directory \"%s\" fallita: %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "rimozione della directory \"%s\" fallita: %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "impossibile creare un collegamento simbolico in \"%s\": %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "rimozione del link simbolico \"%s\" fallita: %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "apertura del file \"%s\" in lettura fallita: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "lettura del file \"%s\" fallita: %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "lettura del file \"%s\" fallita: letti %d di %zu"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "apertura della directory \"%s\" fallita: %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "lettura del link simbolico \"%s\" fallita: %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "la destinazione del link simbolico \"%s\" è troppo lunga"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "\"%s\" è un collegamento simbolico, ma i collegamenti simbolici non sono supportati su questa piattaforma"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "lettura della directory \"%s\" fallita: %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "impossibile chiudere la directory \"%s\": %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "il file di dati \"%s\" nel codice sorgente non è un file normale"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "file di origine duplicato \"%s\""
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "modifica imprevista della pagina per il file non regolare \"%s\""
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "tipo di file sconosciuto per \"%s\""
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "il file \"%s\" è di tipo diverso in origine e destinazione"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "non riuscivo a decidere cosa fare con il file \"%s\""
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "pulizia del search_path fallita: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "full_page_writes dev'essere abilitato nel server di origine"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "non è possibile analizzare il contenuto del file \"%s\""
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "errore nell'esecuzione della query (%s) nel server di origine: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "risultato imprevisto dalla query"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "errore nell'esecuzione della query (%s) nel server di origine: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "risultato non riconosciuto \"%s\" per la posizione di inserimento WAL corrente"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "ricezione della lista dei file fallita: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "risultato imprevisto ricevendo la lista dei file"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "invio della query non riuscito: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "impossibile impostare la connessione libpq in modalità riga singola"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "risultato imprevisto ricevendo i file remoti: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "richiesta di arresto immediate ricevuta"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "dimensione del risultato imprevisto ricevendo i file remoti"
+
+#: libpq_source.c:515
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "tipo di dati imprevisto nel risultato ricevendo i file remoti: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "formato del risultato imprevisto ricevendo i file remoti"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "valori null non previsti nel risultato ricevendo i file remoti"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "lunghezza del risultato non prevista ricevendo i file remoti"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "dati ricevuti per il file \"%s\", quando richiesto per \"%s\""
+
+#: libpq_source.c:570
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "dati ricevuti all'offset %lld del file \"%s\", quando richiesto per l'offset %lld"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "ricevuto più di quanto richiesto per il file \"%s\""
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "numero imprevisto di blocchi di dati ricevuti"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "ricezione del file remoto \"%s\" fallita: %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "set di risultati imprevisti durante il recupero del file remoto \"%s\""
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "impossibile aprire il file sorgente \"%s\": %m"
+
+#: local_source.c:117
+#, c-format
+msgid "size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "dimensione del file di origine \"%s\" modificata contemporaneamente: %d byte previsti, %d copiati"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "chiusura del file \"%s\" fallita: %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "impossibile cercare nel file di origine: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "EOF imprevisto durante la lettura del file \"%s\""
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "Errore nell'allocazione di un processore di lettura del WAL."
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "lettura del record WAL a %X/%X fallita: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "lettura del record WAL a %X/%X fallita"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "il puntatore finale %X/%X non è un punto finale valido; previsto %X/%X"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "impossibile trovare il record WAL precedente a %X/%X: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "impossibile trovare il record WAL precedente a %X/%X"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "spostamento nel file \"%s\" fallito: %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr "Il record WAL modifica una relazione, ma il tipo di record non viene riconosciuto: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s risincronizza un cluster PostgreSQL con un'altra copia del cluster.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"Utilizzo:\n"
+" %s [OPZIONE]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "Opzioni:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal usa restore_command nella configurazione di destinazione in\n"
+" recuperare i file WAL dagli archivi\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=DIRECTORY directory dati esistente da modificare\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=DIRECTORY directory dati di partenza con cui sincronizzare\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=CONNSTR server di origine con cui sincronizzare\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run fermati prima di modificare qualunque cosa\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr ""
+" -N, --no-sync non aspettare che i dati siano scritti con sicurezza\n"
+" sul disco\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress stampa messaggi di avanzamento\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf configurazione di scrittura per la replica\n"
+" (richiede --source-server)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=FILENAME utilizza la configurazione del server principale specificata\n"
+" file durante l'esecuzione del cluster di destinazione\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug stampa una gran quantità di messaggi di debug\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr " --no-ensure-shutdown non corregge automaticamente l'arresto non pulito\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version stampa informazioni sulla versione ed esci\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help mostra questo aiuto ed esci\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"Segnala i bug a <%s>.\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "Pagina iniziale di %s: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "Prova \"%s --help\" per maggiori informazioni."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "nessuna fonte specificata (--source-pgdata o --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "può essere specificato solo uno tra --source-pgdata o --source-server"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "nessuna directory dei dati di destinazione specificata (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "nessuna informazione sul server di origine (--source-server) specificata per --write-recovery-conf"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "troppi argomenti della riga di comando (il primo è \"%s\")"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "non può essere eseguito da \"root\""
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "È obbligatorio eseguire %s come superutente di PostgreSQL."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "lettura dei permessi della directory \"%s\" fallita: %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "connesso al server"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "i cluster di origine e di destinazione sono sulla stessa linea temporale"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "i server sono andati a divergere alla posizione WAL %X/%X sulla timeline %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "rewind non richiesto"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "riavvolgimento dall'ultimo checkpoint comune a %X/%X sulla timeline %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "lettura della lista dei file di origine"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "lettura della lista dei file di destinazione"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "lettura del WAL nella destinazione"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "è necessario copiare %lu MB (la dimensione totale della directory di origine è di %lu MB)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "sincronizzazione della directory dati di destinazione"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "Fatto!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "nessuna azione decisa per il file \"%s\""
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "il sistema sorgente è stato modificato mentre pg_rewind era in esecuzione"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "creazione dell'etichetta di backup e aggiornamento del file di controllo"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "il sistema di origine era in uno stato imprevisto al termine del riavvolgimento"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "i cluster di origine e di destinazione sono di sistemi diversi"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "i cluster non sono compatibili con questa versione di pg_rewind"
+
+#: pg_rewind.c:703
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "il server di destinazione deve utilizzare i checksum dei dati o \"wal_log_hints = on\""
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "il server di destinazione deve essere spento in modo pulito"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "la directory dei dati di origine deve essere chiusa in modo pulito"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s kB (%d%%) copiati"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "file di controllo non valido"
+
+#: pg_rewind.c:918
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "non è stato possibile trovare l'antenato comune delle linee temporali del cluster di origine e di destinazione"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "buffer dell'etichetta di backup troppo piccolo"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "file di controllo imprevisto CRC"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "dimensione del file di controllo imprevista %d, prevista %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "la dimensione del segmento WAL dev'essere una potenza di due tra 1 MB e 1 GB, ma il file di controllo specifica %d byte"
+msgstr[1] "la dimensione del segmento WAL dev'essere una potenza di due tra 1 MB e 1 GB, ma il file di controllo specifica %d byte"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid "program \"%s\" is needed by %s but was not found in the same directory as \"%s\""
+msgstr "il programma \"%s\" è necessario per %s ma non è stato trovato nella stessa directory di \"%s\""
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr "il programma \"%s\" è stato trovato da \"%s\" ma non era della stessa versione di %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "restore_command non è impostato nel cluster di destinazione"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "eseguendo \"%s\" per il server di destinazione per completare il ripristino del crash"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "modalità utente singolo postgres nel cluster di destinazione non riuscita"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "Il comando era: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "errore di sintassi nel file dello storico: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "L'ID della timeline deve essere numerico."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Attesa una locazione di switchpoint del log write-ahead."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "dati non validi nel file dello storico: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "Gli ID della timeline devono essere in ordine crescente."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "dati non validi nel file della cronologia"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "Gli ID della timeline devono avere valori inferiori degli ID della timeline figlia."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "offset del record non valido a %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "contrecord richiesto da %X/%X"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "lunghezza del record a %X/%X non valida: attesa %u, ricevuta %u"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "memoria insufficiente durante il tentativo di decodificare un record di lunghezza %u"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "lunghezza del record %u a %X/%X eccessiva"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "non c'è un flag di contrecord a %X/%X"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "lunghezza contrada non valida %u (prevista %lld) a %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "record mancante a %X/%X"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "ID di gestione risorse %u non valido a %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "record con link-precedente %X/%X non corretto a %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "checksum dei dati del manager di risorse non corretto nel record a %X/%X"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "numero magico %04X non valido nel segmento di log %s, offset %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "bit di info %04X non validi nel segmento di log %s, offset %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "Il file WAL proviene da un sistema di database diverso: l'identificatore del sistema del database del file WAL è %llu, l'identificatore del sistema del database pg_control è %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "il file WAL è di un database diverso: dimensione del segmento errata nell'header della pagina"
+
+#: xlogreader.c:1274
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "il file WAL è di un database diverso: XLOG_BLCKSZ non corretto nell'header di pagina"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "pageaddr inaspettato %X/%X nel segmento di log %s, offset %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "ID della timeline %u (dopo %u) fuori sequenza nel segmento di log %s, offset %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "block_id fuori sequenza %u a %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA impostato, ma dati non inclusi a %X/%X"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA non impostato, ma la lunghezza dei dati è %u a %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE impostato, ma offset buco %u lunghezza %u lunghezza dell'immagine del blocco %u a %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE non impostato, ma offset buco %u lunghezza %u a %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_COMPRESSED impostato, ma blocca la lunghezza dell'immagine %u a %X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "né BKPIMAGE_HAS_HOLE né BKPIMAGE_COMPRESSED impostati, ma la lunghezza dell'immagine del blocco è %u a %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_REL impostato ma non c'è un rel precedente a %X/%X"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "block_id %u non valido a %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "record con lunghezza non valida a %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "impossibile individuare il blocco di backup con ID %d nel record WAL"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "impossibile ripristinare l'immagine in %X/%X con il blocco %d non valido specificato"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "impossibile ripristinare l'immagine in %X/%X con stato non valido, blocco %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid "could not restore image at %X/%X compressed with %s not supported by build, block %d"
+msgstr "impossibile ripristinare l'immagine in %X/%X compressa con %s non supportata da build, blocco %d"
+
+#: xlogreader.c:2111
+#, c-format
+msgid "could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "impossibile ripristinare l'immagine in %X/%X compressa con metodo sconosciuto, blocco %d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "impossibile decomprimere l'immagine in %X/%X, blocco %d"
+
+#~ msgid " block %u\n"
+#~ msgstr " blocco %u\n"
+
+#~ msgid "\"%s\" is not a directory\n"
+#~ msgstr "\"%s\" non è una directory\n"
+
+#~ msgid "\"%s\" is not a regular file\n"
+#~ msgstr "\"%s\" non è un file regolare\n"
+
+#~ msgid "\"%s\" is not a symbolic link\n"
+#~ msgstr "\"%s\" non è un link simbolico\n"
+
+#~ msgid "%d: %X/%X - %X/%X\n"
+#~ msgstr "%d: %X/%X - %X/%X\n"
+
+#~ msgid "%s (%s)\n"
+#~ msgstr "%s (%s)\n"
+
+#~ msgid "%s: could not read permissions of directory \"%s\": %s\n"
+#~ msgstr "%s: lettura dei permessi della directory \"%s\" fallita: %s\n"
+
+#~ msgid "Expected a numeric timeline ID.\n"
+#~ msgstr "Atteso un ID numerico di timeline.\n"
+
+#~ msgid "Expected a write-ahead log switchpoint location.\n"
+#~ msgstr "Attesa una locazione di switchpoint del log write-ahead.\n"
+
+#~ msgid "Failure, exiting\n"
+#~ msgstr "Errore, uscita\n"
+
+#~ msgid "Source timeline history:\n"
+#~ msgstr "Storia della timeline di origine:\n"
+
+#~ msgid "Target timeline history:\n"
+#~ msgstr "Storia della timeline di destinazione:\n"
+
+#~ msgid ""
+#~ "The program \"initdb\" is needed by %s but was\n"
+#~ "not found in the same directory as \"%s\".\n"
+#~ "Check your installation.\n"
+#~ msgstr ""
+#~ "Il programma \"initdb\" è richiesto da %s ma non è\n"
+#~ "stato tro vato nella stessa directory di \"%s\".\n"
+#~ "Controlla la tua installazione.\n"
+
+#~ msgid ""
+#~ "The program \"initdb\" was found by \"%s\"\n"
+#~ "but was not the same version as %s.\n"
+#~ "Check your installation.\n"
+#~ msgstr ""
+#~ "Il programma \"initdb\" è stato trovato da \"%s\"\n"
+#~ "ma non è la stessa versione di %s.\n"
+#~ "Controlla la tua installazione.\n"
+
+#~ msgid "Timeline IDs must be in increasing sequence.\n"
+#~ msgstr "Gli ID di timeline devono essere in sequenza crescente.\n"
+
+#~ msgid "Timeline IDs must be less than child timeline's ID.\n"
+#~ msgstr "Gli ID della timeline devono essere meno dell'ID della timeline del figlio.\n"
+
+#~ msgid "Try \"%s --help\" for more information.\n"
+#~ msgstr "Prova \"%s --help\" per maggiori informazioni.\n"
+
+#~ msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte\n"
+#~ msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes\n"
+#~ msgstr[0] "la dimensione del semgento WAL deve essere una potenza di due tra 1 MB e 1 GB, ma il file di controllo specifica %d byte\n"
+#~ msgstr[1] "la dimensione del semgento WAL deve essere una potenza di due tra 1 MB e 1 GB, ma il file di controllo specifica %d byte\n"
+
+#~ msgid "could not close file \"%s\": %s\n"
+#~ msgstr "chiusura del file \"%s\" fallita: %s\n"
+
+#~ msgid "could not connect to server: %s"
+#~ msgstr "connessione al server fallita: %s"
+
+#~ msgid "could not create directory \"%s\": %s\n"
+#~ msgstr "creazione della directory \"%s\" fallita: %s\n"
+
+#~ msgid "could not create temporary table: %s"
+#~ msgstr "creazione della tabella temporanea fallita: %s"
+
+#~ msgid "could not open directory \"%s\": %s\n"
+#~ msgstr "apertura della directory \"%s\" fallita: %s\n"
+
+#~ msgid "could not open file \"%s\" for reading: %s\n"
+#~ msgstr "apertura del file \"%s\" in lettura fallita: %s\n"
+
+#~ msgid "could not open file \"%s\": %s\n"
+#~ msgstr "apertura del file \"%s\" fallita: %s\n"
+
+#~ msgid "could not read directory \"%s\": %s\n"
+#~ msgstr "lettura della directory \"%s\" fallita: %s\n"
+
+#~ msgid "could not read file \"%s\": %s\n"
+#~ msgstr "lettura del file \"%s\" fallita: %s\n"
+
+#~ msgid "could not read from file \"%s\": %s\n"
+#~ msgstr "lettura dal file \"%s\" fallita: %s\n"
+
+#~ msgid "could not read symbolic link \"%s\": %s\n"
+#~ msgstr "lettura del link simbolico \"%s\" fallita: %s\n"
+
+#~ msgid "could not remove directory \"%s\": %s\n"
+#~ msgstr "rimozione della directory \"%s\" fallita: %s\n"
+
+#~ msgid "could not remove file \"%s\": %s\n"
+#~ msgstr "rimozione del file \"%s\" fallita: %s\n"
+
+#~ msgid "could not remove symbolic link \"%s\": %s\n"
+#~ msgstr "rimozione del link simbolico \"%s\" fallita: %s\n"
+
+#~ msgid "could not seek in file \"%s\": %s\n"
+#~ msgstr "spostamento nel file \"%s\" fallito: %s\n"
+
+#~ msgid "could not send COPY data: %s"
+#~ msgstr "invio dei dati di COPY fallito: %s"
+
+#~ msgid "could not send end-of-COPY: %s"
+#~ msgstr "invio del fine-COPY fallito: %s"
+
+#~ msgid "could not send file list: %s"
+#~ msgstr "invio della lista dei file fallito: %s"
+
+#~ msgid "could not set up connection context: %s"
+#~ msgstr "preparazione del contesto di connessione fallita: %s"
+
+#~ msgid "could not stat file \"%s\": %s\n"
+#~ msgstr "richiesta informazioni sul file \"%s\" fallita: %s\n"
+
+#~ msgid "could not truncate file \"%s\" to %u: %s\n"
+#~ msgstr "troncamento del file \"%s\" a %u fallito: %s\n"
+
+#~ msgid "could not write file \"%s\": %s\n"
+#~ msgstr "scrittura nel file \"%s\" fallita: %s\n"
+
+#~ msgid "entry \"%s\" excluded from source file list\n"
+#~ msgstr "voce \"%s\" esclusa dalla lista di file sorgenti\n"
+
+#~ msgid "entry \"%s\" excluded from target file list\n"
+#~ msgstr "voce \"%s\" esclusa dalla lista di file di destinazione\n"
+
+#~ msgid "fetched file \"%s\", length %d\n"
+#~ msgstr "ricevuto il file \"%s\", lunghezza %d\n"
+
+#~ msgid "getting file chunks\n"
+#~ msgstr "ricezione blocchi del file\n"
+
+#~ msgid "invalid data in history file: %s\n"
+#~ msgstr "dati non validi nel file di storia: %s\n"
+
+#~ msgid "received null value for chunk for file \"%s\", file has been deleted\n"
+#~ msgstr "ricevuto valore null per il blocco del file \"%s\", il file è stato cancellato\n"
+
+#~ msgid "source file list is empty\n"
+#~ msgstr "la lista dei file di origine è vuota\n"
+
+#~ msgid "source server must not be in recovery mode\n"
+#~ msgstr "il server di origine non dev'essere in modalità di recupero\n"
+
+#~ msgid "symbolic link \"%s\" target is too long\n"
+#~ msgstr "destinazione del link simbolico \"%s\" troppo lunga\n"
+
+#~ msgid "sync of target directory failed\n"
+#~ msgstr "sincronizzazione della directory di destinazione fallita\n"
+
+#~ msgid "syntax error in history file: %s\n"
+#~ msgstr "errore di sintassi nel file di storia: %s\n"
+
+#~ msgid "unexpected result while sending file list: %s"
+#~ msgstr "risultato imprevisto inviando la lista dei file: %s"
diff --git a/src/bin/pg_rewind/po/ja.po b/src/bin/pg_rewind/po/ja.po
new file mode 100644
index 0000000..2dbbf29
--- /dev/null
+++ b/src/bin/pg_rewind/po/ja.po
@@ -0,0 +1,1009 @@
+# pg_rewind.po
+# Japanese message translation file for pg_rewind
+#
+# Copyright (C) 2016-2022 PostgreSQL Global Development Group
+#
+# This file is distributed under the same license as the PostgreSQL package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL 15)\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2022-09-26 11:14+0900\n"
+"PO-Revision-Date: 2022-09-26 14:53+0900\n"
+"Last-Translator: Kyotaro Horiguchi <horikyota.ntt@gmail.com>\n"
+"Language-Team: Japan PostgreSQL Users Group <jpug-doc@ml.postgresql.jp>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.13\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "エラー: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "警告: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "詳細: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "ヒント: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "メモリ不足です\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "null ポインタを複製できません(内部エラー)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "ライブラリ\"%s\"をロードできませんでした: エラーコード %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "このプラットフォームでは制限付きトークンを生成できません: エラーコード %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "プロセストークンをオープンできませんでした: エラーコード %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "SIDを割り当てられませんでした: エラーコード %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "制限付きトークンを作成できませんでした: エラーコード %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "\"%s\"コマンドのプロセスを起動できませんでした: エラーコード %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "制限付きトークンで再実行できませんでした: %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "サブプロセスの終了コードを取得できませんでした。: エラーコード %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "%%r置換を含むrestore_commandは使用できません"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "想定外の\"%1$s\"のファイルサイズ: %3$lld ではなく %2$lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "アーカイブからリストアされたファイル\"%s\"のオープンに失敗しました: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "ファイル\"%s\"のstatに失敗しました: %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "restore_commandが失敗しました: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "ファイル\"%s\"をアーカイブからリストアできませんでした"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "メモリ不足です"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "ファイル\"%s\"をオープンできませんでした: %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "ファイル\"%s\"を書き出せませんでした: %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "ファイル\"%s\"を作成できませんでした: %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "ターゲットファイル\"%s\"をオープンできませんでした: %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "ターゲットファイル\"%s\"をクローズできませんでした: %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "ターゲットファイル\"%s\"をシークできませんでした: %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "ファイル\"%s\"を書き出せませんでした: %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "\"%s\"に対する未定義のファイルタイプ"
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "通常のファイルに対する不正なアクション(CREATE)です"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "ファイル\"%s\"を削除できませんでした: %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "ファイル\"%s\"を切り詰めのためにオープンできませんでした: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "ファイル\"%s\"を%uバイトに切り詰められませんでした: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "ディレクトリ\"%s\"を作成できませんでした: %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "ディレクトリ\"%s\"を削除できませんでした: %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "\"%s\"にシンボリックリンクを作成できませんでした: %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "シンボリックリンク\"%s\"を削除できませんでした: %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "ファイル\"%s\"を読み取り用にオープンできませんでした: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "ファイル\"%s\"の読み取りに失敗しました: %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "ファイル\"%1$s\"を読み込めませんでした: %3$zuバイトのうち%2$dバイトを読み込みました"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "ディレクトリ\"%s\"をオープンできませんでした: %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "シンボリックリンク\"%s\"を読めませんでした: %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "シンボリックリンク\"%s\"の参照先が長すぎます"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "\"%s\"はシンボリックリンクですが、このプラットフォームではシンボリックリンクをサポートしていません"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "ディレクトリ\"%s\"を読み取れませんでした: %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "ディレクトリ\"%s\"をクローズできませんでした: %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "ソースのデータファイル\"%s\"は通常のファイルではありません"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "ソースファイル\"%s\"が重複しています"
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "非通常ファイル\"%s\"に対する想定外のページの書き換えです"
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "\"%s\"に対する未知のファイルタイプ"
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "ファイル\"%s\"はソースとターゲットとで異なるタイプです"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "ファイル\"%s\"の処理を決定できませんでした"
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "search_pathを消去できませんでした: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "ソースサーバーではfull_pate_writesは有効でなければなりません"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "ファイル内容を取得するための文を準備できませんでした: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "ソースサーバーで実行中のクエリ(%s)でエラー: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "クエリから想定外の結果セット"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "ソースサーバーの実行中のクエリ(%s)でエラー: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "現在のWAL挿入位置として認識不可の結果\"%s\""
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "ファイルリストをフェッチできませんでした: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "ファイルリストのフェッチ中に想定外の結果セット"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "クエリを送信できませんでした: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "libpq接続を単一行モードに設定できませんでした"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "リモートファイルをフェッチ中に想定外の結果: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "要求よりも多くのデータチャンクが到着しました"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "リモートファイルのフェッチ中に想定外の結果セットサイズ"
+
+#: libpq_source.c:515
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "リモートファイルのフェッチ中の結果セットに想定外のデータ型: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "リモートファイルのフェッチ中に想定外の結果形式"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "リモートファイルのフェッチ中の結果に想定外のNULL値"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "リモートファイルのフェッチ中に想定外の結果の長さ"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "ファイル\"%s\"への要求に対してファイル\"%s\"のデータを受信しました"
+
+#: libpq_source.c:570
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "ファイル\"%2$s\"のオフセット%3$lldへの要求に対してオフセット%1$lldのデータを受信しました"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "ファイル”%s\"に対して要求よりも多量のデータを受信しました"
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "想定外の数のデータチャンクを受信しました"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "リモートファイル\"%s\"をフェッチできませんでした: %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "リモートファイル\"%s\"のフェッチ中に想定外の結果セット"
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "ソースファイル\"%s\"をオープンすることができませんでした: %m"
+
+#: local_source.c:117
+#, c-format
+msgid "size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "ファイル\"%s\"のサイズが同時に変更されました。%dバイトを期待していましたが、%dバイトコピーされました"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "ファイル\"%s\"をクローズできませんでした: %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "ソースファイルをシークすることができませんでした: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "ファイル\"%s\"を読み込み中に想定外のEOF"
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "WAL読み取り機構のメモリ割り当て中にメモリ不足"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "%X/%XのWALレコードを読み取れませんでした: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "%X/%XのWALレコードを読み取れませんでした"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "終了点%X/%Xは妥当な終了点ではありません; %X/%Xを期待していました"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "%X/%Xの前のWALレコードが見つかりませんでした: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "%X/%Xの前のWALレコードが見つかりませんでした"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "ファイル\"%s\"をシークできませんでした: %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr "WALレコードはリレーションを更新しますが、レコードの型を認識できません: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s はPostgreSQLクラスタをそのクラスタのコピーで再同期します。\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"使用方法:\n"
+" %s [オプション]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "オプション:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal ターゲットの設定の中のrestore_commandを使用して\n"
+" アーカイブからWALファイルを取得する\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=DIRECTORY 修正を行う既存データディレクトリ\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=DIRECTORY 同期元とするデータディレクトリ\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=CONNSTR 同期元とするサーバー\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run 修正を始める前に停止する\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr " -N, --no-sync 変更のディスクへの安全な書き出しを待機しない\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress 進捗メッセージを出力\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf レプリケーションのための設定を書き込む\n"
+" (--source-server が必要となります)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=FILENAME ターゲットのクラスタの実行時に指定した\n"
+" 主サーバー設定ファイルを使用する\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug 多量のデバッグメッセージを出力\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr " --no-ensure-shutdown 非クリーンシャットダウン後の修正を自動で行わない\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version バージョン情報を表示して終了\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help このヘルプを表示して終了\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"バグは<%s>に報告してください。\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "%s ホームページ: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "詳細は\"%s --help\"を実行してください。"
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "ソースが指定されていません(--source-pgdata または --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "--source-pgdataか--source-server はいずれか一方のみ指定可能です"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "ターゲットデータディレクトリが指定されていません(--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "--write-recovery-confにソースサーバー情報(--source-server)が指定されていません"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr " コマンドライン引数が多すぎます(先頭は\"%s\")"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "\"root\"では実行できません"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "PostgreSQLのスーパーユーザーで%sを実行しなければなりません"
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "ディレクトリ\"%s\"の権限を読み取れませんでした: %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "サーバーへ接続しました"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "ソースとターゲットのクラスタが同一タイムライン上にあります"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "タイムライン%3$uのWAL位置%1$X/%2$Xで両サーバーが分岐しています"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "巻き戻しは必要ありません"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "タイムライン%3$uの%1$X/%2$Xにある最新の共通チェックポイントから巻き戻しています"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "ソースファイルリストを読み込んでいます"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "ターゲットファイルリストを読み込んでいます"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "ターゲットでWALを読み込んでいます"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "%lu MBコピーする必要があります(ソースディレクトリの合計サイズは%lu MBです)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "ターゲットデータディレクトリを同期しています"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "完了!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "ファイル\"%s\"に対するアクションが決定されていません"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "pg_rewindの実行中にソースシス7テムが更新されました"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "backup labelを作成して制御ファイルを更新しています"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "巻き戻し完了時点のソースシステムが想定外の状態でした"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "ソースクラスタとターゲットクラスタは異なるシステムのものです"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "クラスタは、このバージョンのpg_rewindとの互換性がありません"
+
+#: pg_rewind.c:703
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "ターゲットサーバーはデータチェックサムを利用している、または\"wal_log_hints = on\"である必要があります"
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "ターゲットサーバーはきれいにシャットダウンされていなければなりません"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "ソースデータディレクトリはきれいにシャットダウンされていなければなりません"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s kB (%d%%) コピーしました"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "不正な制御ファイル"
+
+#: pg_rewind.c:918
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "ソースクラスタとターゲットクラスタのタイムラインの共通の祖先を見つけられません"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "バックアップラベルのバッファが小さすぎます"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "想定外の制御ファイルCRCです"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "想定外の制御ファイルのサイズ%d、想定は%d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "WALセグメントのサイズ指定は1MBと1GBの間の2の累乗でなければなりません、しかしコントロールファイルでは%dバイトとなっています"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid "program \"%s\" is needed by %s but was not found in the same directory as \"%s\""
+msgstr "%2$sには\"%1$s\"プログラムが必要ですが、\"%3$s\"と同じディレクトリにありませんでした。"
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr "\"%2$s\"がプログラム\"%1$s\"を見つけましたが、これは%3$sと同じバージョンではありませんでした。"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "ターゲットクラスタでrestore_commandが設定されていません"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "ターゲットサーバーに対して\"%s\"を実行してクラッシュリカバリを完了させます"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "ターゲットクラスタでのpostgresコマンドのシングルユーザーモード実行に失敗しました"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "コマンド: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "履歴ファイル内の構文エラー: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "数字のタイムラインIDを想定しました。"
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "先行書き込みログの切り替え点の場所があるはずでした。"
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "履歴ファイル内の不正なデータ: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "タイムラインIDは昇順でなければなりません"
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "履歴ファイル内の無効なデータ"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "タイムラインIDは子のタイムラインIDより小さくなければなりません。"
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "%X/%Xのレコードオフセットが無効です"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "%X/%Xではcontrecordが必要です"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "%X/%Xのレコード長が無効です:長さは%uである必要がありますが、長さは%uでした"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "長さ%uのレコードのデコード中のメモリ不足"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "%2$X/%3$Xのレコード長%1$uが大きすぎます"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "%X/%Xで contrecord フラグがありません"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "%3$X/%4$Xの継続レコードの長さ%1$u(正しくは%2$lld)は不正です"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "%X/%Xに継続レコードがありません"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "%2$X/%3$XのリソースマネージャID %1$uが無効です"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "直前のリンク%1$X/%2$Xが不正なレコードが%3$X/%4$Xにあります"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "%X/%Xのレコード内のリソースマネージャデータのチェックサムが不正です"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "ログセグメント%2$s、オフセット%3$uのマジックナンバー%1$04Xは無効です"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "ログセグメント %2$s、オフセット %3$u の情報ビット %1$04X は無効です"
+
+#: xlogreader.c:1260
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "WALファイルは異なるデータベースシステム由来のものです: WALファイルのデータベースシステム識別子は %lluで、pg_control におけるデータベースシステム識別子は %lluです"
+
+#: xlogreader.c:1268
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "WAL ファイルは異なるデータベースシステム由来のものです: ページヘッダーのセグメントサイズが正しくありません"
+
+#: xlogreader.c:1274
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "WAL ファイルは異なるデータベースシステム由来のものです: ページヘッダーのXLOG_BLCKSZが正しくありません"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "ログセグメント%3$s、オフセット%4$uのページアドレス%1$X/%2$Xは想定外です"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "ログセグメント%3$s、オフセット%4$uの時系列ID %1$u(%2$uの後)は順序に従っていません"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "block_id %uが%X/%Xで無効です"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATAが設定されていますが、%X/%Xにデータがありません"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATAが設定されていませんが、%2$X/%3$Xのデータ長は%1$u"
+
+#: xlogreader.c:1802
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLEが設定されていますが、%4$X/%5$Xでホールオフセット%1$u、長さ%2$u、ブロックイメージ長%3$u"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLEが設定されていませんが、%3$X/%4$Xにホールオフセット%1$u、長さ%2$u"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_COMPRESSEDが設定されていますが、%2$X/%3$Xにおいてブロックイメージ長が%1$uです"
+
+#: xlogreader.c:1847
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLEもBKPIMAGE_COMPRESSEDも設定されていませんが、%2$X/%3$Xにおいてブロックイメージ長が%1$uです"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_RELが設定されていますが、%X/%Xにおいて以前のリレーションがありません"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "%2$X/%3$Xにおけるblock_id %1$uが無効です"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "%X/%Xのレコードのサイズが無効です"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "WALレコード中のID %dのバックアップブロックを特定できませんでした"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "%X/%Xで不正なブロック%dが指定されているためイメージが復元できませんでした"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "%X/%Xでブロック%dのイメージが不正な状態であるため復元できませんでした"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid "could not restore image at %X/%X compressed with %s not supported by build, block %d"
+msgstr "%1$X/%2$Xで、ブロック%4$dがこのビルドでサポートされない圧縮方式%3$sで圧縮されているため復元できませんでした"
+
+#: xlogreader.c:2111
+#, c-format
+msgid "could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "%X/%Xでブロック%dのイメージが不明な方式で圧縮されているため復元できませんでした"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "%X/%Xのブロック%dが伸張できませんでした"
diff --git a/src/bin/pg_rewind/po/ka.po b/src/bin/pg_rewind/po/ka.po
new file mode 100644
index 0000000..51cbc16
--- /dev/null
+++ b/src/bin/pg_rewind/po/ka.po
@@ -0,0 +1,1101 @@
+# Georgian message translation file for pg_rewind
+# Copyright (C) 2022 PostgreSQL Global Development Group
+# This file is distributed under the same license as the pg_rewind (PostgreSQL) package.
+# Temuri Doghonadze <temuri.doghonadze@gmail.com>, 2022.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL) 15\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2022-09-25 19:51+0000\n"
+"PO-Revision-Date: 2022-09-25 22:11+0200\n"
+"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n"
+"Language-Team: Georgian <nothing>\n"
+"Language: ka\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 3.1.1\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "შეცდომა: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "გაფრთხილება: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "დეტალები: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "მინიშნება: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "არასაკმარისი მეხსიერება\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "ნულოვანი მაჩვენებლის დუბლირება შეუძლებელია (შიდა შეცდომა)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "ბიბლიოთეკის (\"%s\") ჩატვირთვის შეცდომა: შეცდომის კოდი: %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "ამ პლატფორმაზე შეზღუდული კოდების შექმნა შეუძლებელია: შეცდომის კოდი %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "პროცესის კოდის გახსნა შეუძლებელია: შეცდომის კოდი %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "შეცდომა SSID-ების გამოყოფისას: შეცდომის კოდი %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "შეზღუდული კოდის შექმნა ვერ მოხერხდა: შეცდომის კოდი %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "„%s“ ბრძანების პროცესის დაწყება ვერ მოხერხდა: შეცდომის კოდი %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "შეზღუდულ კოდის ხელახლა შესრულება ვერ მოხერხდა: შეცდომის კოდი %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "ქვეპროცესიდან გასასვლელი კოდი ვერ მივიღე: შეცდომის კოდი %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr ""
+"restore_command-ის გამოყენება %%r ადგილმჭერის გარეშე გამოყენება შეუძლებელია"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "\"%s\"-ის მოულოდნელი ზომა: %lld %lld-ის მაგიერ"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "არქივიდან აღდგენილი ფაილის (\"%s\") გახსნის შეცდომა: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "ფაილი \"%s\" არ არსებობს: %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "აღდგენის_ბრძანების შეცდომა: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "\"%s\"-ის არქივიდან აღდგენის შეცდომა"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "არასაკმარისი მეხსიერება"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "ფაილის (%s) გახსნის შეცდომა: %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "ფაილში (%s) ჩაწერის შეცდომა: %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "ფაილის (%s) შექმნის შეცდომა: %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "სამიზნე ფაილის (%s) გახსნის შეცდომა: %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "სამიზნე ფაილის (%s) დახურვის შეცდომა: %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "სამიზნე ფაილში (%s) გადახვევის შეცდომა: %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "ფაილში (%s) ჩაწერის შეცდომა: %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "%s: ფაილის არასწორი ტიპი"
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "არასწორი ქმედება (CREATE) ჩვეულებრივი ფაილისთვის"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "ფაილის წაშლის შეცდომა \"%s\": %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "წასაკვეთი ფაილის (%s) გახსნის შეცდომა: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "ფაილის (%s) %u-მდე მოკვეთის შეცდომა: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "საქაღალდის (%s) შექმნის შეცდომა: %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "საქაღალდის (\"%s\") წაშლის შეცდომა: %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "სიმბმულის შექმნის შეცდომა %s: %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "სიმბმულის წაშლის შეცდომა %s: %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "ფაილის (%s) გახსნის შეცდომა: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "ფაილის (%s) წაკითხვის შეცდომა: %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "\"%s\"-ის წაკითხვის შეცდომა: წაკითხულია %d %zu-დან"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "საქაღალდის (%s) გახსნის შეცდომა: %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "სიმბოლური ბმის \"%s\" წაკითხვის შეცდომა: %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "%s: სიმბმული ძალიან გრძელია"
+
+#: file_ops.c:464
+#, c-format
+msgid ""
+"\"%s\" is a symbolic link, but symbolic links are not supported on this "
+"platform"
+msgstr ""
+"%s სიმბმულია, მაგრამ სიმბოლური ბმულები ამ პლატფორმაზე მხარდაჭერილი არაა"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "საქაღალდის (%s) წაკითხვის შეცდომა: %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "საქაღალდის %s-ზე დახურვის შეცდომა: %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "წყაროში არსებული მონაცემების ფალი \"%s\" ჩვეულებრივი ფაილი არაა"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "დუბლირებული საწყისი ფაილი : \"%s\""
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "არაჩვეულებრივი ფაილის (%s) გვერდების მოულოდნელი ცვლილება"
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "ფაილის უცნობი ტიპი \"%s\"."
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "ფაილი %s წყაროში და სამიზნეში სხვადასხვა ტიპისაა"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "ვერ გადავწყვიტე, ფაილს რა ვუყო: %s"
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "search_path-ის გასუფთავების პრობლემა: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "საწყის სერვერზე full_page_writes-ის ჩართვა აუცილებელია"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "შეცდომა ფაილის შემცველობის გამოსათხოველი ოპერაციების მომზადებისას: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "შეცდომა სერვერზე (%2$s) მოთხოვნის (%1$s) შესრულებისას"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "მოთხოვნის მოულოდნელი სედეგი"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "შეცდომა სერვერში (%2$s) მოთხოვნის (%1$s) შესრულებისას"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "უცნობი პასუხი მიმდინარე WAL ჩასმის მდებარეობისთვის: %s"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "ფაილების სიის მიღების პრობლემა: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "მოულოდნელი პასუხი ფაილების სიის მიღებისას"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "მოთხოვნის გაგზავნის პრობლემა: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "ერთმწკრივიან რეჟიმში libpq შეერთების დაყენება შეუძლებელია"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "დაშორებული ფაილების მიღების მოულოდნელი შედეგი: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "მიღებულია მეტი ნაგლეჯი, ვიდრე მოვითხოვე"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "ფაილების გამოთხოვისას მიღებული შედეგების სეტის მოულოდნელი ზომა"
+
+#: libpq_source.c:515
+#, c-format
+msgid ""
+"unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr ""
+"მონაცემების მოულოდნელი ტიპები დაშორებული ფაილების გამოთხოვისას შედეგების "
+"სეტში: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "დაშორებული ფაილების მიღებისას მიღებული ფორმატი მოულოდნელია"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr ""
+"დაშორებული ფაილების მიღების შედეგი მოულოდნელ ნულოვან მნიშვნელობებს შეიცავს"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "დაშორებული ფაილის მიღებისას მიღებული შედეგის სიგრძე არასწორია"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "მიღებულია მონაცემები ფაილისთვის \"%s\", მაშინ, როცა მოვითხოვე \"%s\""
+
+#: libpq_source.c:570
+#, c-format
+msgid ""
+"received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr ""
+"მონაცემები მიღებულია წანაცვლებისთვის %lld ფაილში %s მაშინ, როცა მოთხოვნილი "
+"იყო წანაცვლებისთვის %lld"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "მიღებულია მეტი, ვიდრე მოთხოვნილია ფაილისთვის: %s"
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "მონაცემების მიღებული ნაწილების რიცხვი არასწორია"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "დაშორებული ფაილის (%s) მიღების შეცდომა: %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "მოულოდნელი პასუხი დაშორებული ფაილის (%s) მიღებისას"
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "წყაროს ფაილის \"%s\" გახსნის შეცდომა: %m"
+
+#: local_source.c:117
+#, c-format
+msgid ""
+"size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "ფაილის (%s) ზომა პარალელურად შეიცვალა: მოველოდი %d ბაიტს. დაკოპირდა %d"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "ფაილის (%s) დახურვის შეცდომა: %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "საწყის ფაილში გადახვევის პრობლემა: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "მოულოდნელი EOF ფაილის კითხვისას: %s"
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "არასაკმარისი მეხსიერება WAL-ის წამკითხავი პროცესორისთვის"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "შეცდომა WAL ჩანაწერის კითხვისას: %X/%X: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "შეცდომა WAL ჩანაწერის კითხვისას: %X/%X"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "ბოლოს მაჩვენებელი %X/%X არასწორი ბოლოს მაჩვენებელია. მოველოდი %X/%X"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "წინა WAL ჩანაწერის პოვნა შეუძლებელია მისამართზე %X/%X: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "წინა WAL ჩანაწერის პოვნა შეუძლებელია მისამართზე %X/%X"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "ფაილში (%s) გადახვევის პრობლემა: %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid ""
+"WAL record modifies a relation, but record type is not recognized: lsn: %X/"
+"%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr ""
+"WAL ჩანაწერი ცვლის ურთიერთობას, მაგრამ ჩანაწერის ტიპი უცნობია: lsn: %X/%X, "
+"rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s PostgreSQL კლასტერის მის ასლთან სინქრონიზაციას ახდენს.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"გამოყენება:\n"
+" %s [პარამეტრი]..\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "პარამეტრები:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration "
+"to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal არქივიდან WAL ფაილების მისაღებად სამიზნე "
+"კონფიგურაციაში \n"
+" restore_command -ის გამოყენება\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=საქაღალდე მონაცემების საქაღალდე ჩასასწორებლად\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid ""
+" --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=საქაღალდედასასინქრონებელი საწყისი საქაღალდე\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=CONNSTR დასასინქრონებელი საწყისი სერვერი\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run გაჩერება, სანამ რამე შეიცვლება\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr ""
+" -N, --no-sync არ დაველოდო ცვლილებების\n"
+" დისკზე უსაფრთხოდ ჩაწერას\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress მიმდინარეობის ინფორმაციის ჩვენება\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf რეპლიკაციის კონფიგურაციის ჩაწერა\n"
+" (მოითხოვს --source-server)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=FILENAME სამიზნეკ ლასტერის გაშვებისას მთავარი \n"
+" სერვერის მითითებული კონფიგურაციის ფაილსი გამოყენება\n"
+"\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr ""
+" --debug პროგრამის გასამართი შეტყობინებების "
+"გამოტანა\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid ""
+" --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr ""
+" --no-ensure-shutdown არ სცადო არასწორად გამორთვის შედეგების "
+"გასწორება\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid ""
+" -V, --version output version information, then exit\n"
+msgstr " -V, --version ვერსიის ინფორმაციის გამოტანა და გასვლა\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help ამ დახმარების ჩვენება და გასვლა\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"შეცდომების შესახებ მიწერეთ: %s\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "%s-ის საწყისი გვერდია: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "მეტი ინფორმაციისთვის სცადეთ '%s --help'."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "წყარო მითითებული არაა (--source-pgdata ან --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "შეიძლება მხოლოდ ერთის, --source-pgdata ან --source-server -ის მითითება"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "სამიზნე საქაღალდე მითითებული არაა (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid ""
+"no source server information (--source-server) specified for --write-"
+"recovery-conf"
+msgstr ""
+"საწყისი სერვერის ინფორმაცია (--source-server) პარამეტრსთვის --write-recovery-"
+"conf მითითებული არაა"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "მეტისმეტად ბევრი ბრძანების-სტრიქონის არგუმენტი (პირველია \"%s\")"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "root-ით ვერ გაეშვება"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "%s PostgreSQL-ის ზემომხმარებლით უნდა გაუშვათ."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "საქაღალდის წვდომების წაკითხვა შეუძლებელია \"%s\": %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "სერვერთან მიერთება წარმატებულია"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "საწყისი და სამიზნე კლასტერები იგივე დროის ხაზზეა"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "სერვერი დაშორდა WAL-ს მდებარეობაზე %X/%X დროის ხაზზე %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "გადახვევა საჭირო არაა"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr ""
+"გადახვევა ბოლო საერთო საკონტროლო წერტილიდან მისამართზე %X/%X დროის ხაზზე %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "ფაილების წყაროს სიის კითხვა"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "სამიზნის ფაილების სიის კითხვა"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "სამიზნეში მყოფი WAL-ის კითხვა"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "საჭიროა %lu მბ-ის კოპირება (საწყის საქაღალდის სრული ზომაა %lu მბ)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "მონაცემების სამიზე საქაღალდის სინქრონიზაცია"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "შესრულებულია!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "ფაილისთვის %s ქმედება არჩეული არაა"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "საწყისი ფაილი შეიცვალა, სანამ pg_rewind იყო გაშვებული"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "მარქაფის ჭდის შექმნა და საკონტროლო ფაილის განახლება"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "საწყისი სისტემა გადახვევისას გაურკვეველ მდგომარეობაში აღმოჩნდა"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "საწყისი და სამიზნე კლასტერები სხვადასახვა სისტემებიდანაა"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "კლასტერები pg_rewind-ის ამ ვერსიასთან შეუთავსებელია"
+
+#: pg_rewind.c:703
+#, c-format
+msgid ""
+"target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr ""
+"სამზნე სერვერზე საჭიროა ან მონაცემების საკონტროლო ჯამების გამოყენება, ან "
+"\"wal_log_hints = on\""
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "სამიზნე ბაზა წესების დაცვით უნდა იყოს გამორთული"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "საწყისი ბაზა წესების დაცვით უნდა იყოს გამორთული"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s კბ (%d%%) დაკოპირდა"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "არასწორი კონტროლის ფაილი"
+
+#: pg_rewind.c:918
+#, c-format
+msgid ""
+"could not find common ancestor of the source and target cluster's timelines"
+msgstr ""
+"საწყისი და სამიზნე კლასტერების დროის ხაზის საერთო წინაპრის პოვნა შეუძლებელია"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "მარქაფის ჭდის ბაფერი ძალიან პატარაა"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "კონტროლის ფაილის მოულოდნელი CRC"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "საკონტროლო ფაილის არასწორი სიგრძე: %d. უნდა იყოს: %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid ""
+"WAL segment size must be a power of two between 1 MB and 1 GB, but the "
+"control file specifies %d byte"
+msgid_plural ""
+"WAL segment size must be a power of two between 1 MB and 1 GB, but the "
+"control file specifies %d bytes"
+msgstr[0] ""
+"WAL სეგმენტის ზომა ორის ხარისხი უნდა იყოს, 1 მბ-სა და 1გბ-ს შორის, მაგრამ "
+"კონტროლის ფაილში მითითებულია %d ბაიტი"
+msgstr[1] ""
+"WAL სეგმენტის ზომა ორის ხარისხი უნდა იყოს, 1 მბ-სა და 1გბ-ს შორის, მაგრამ "
+"კონტროლის ფაილში მითითებულია %d ბაიტი"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid ""
+"program \"%s\" is needed by %s but was not found in the same directory as "
+"\"%s\""
+msgstr ""
+"პროგრამა \"%s\" სჭირდება \"%s\"-ს, მაგრამ იგივე საქაღალდეში, სადაც \"%s\", "
+"ნაპოვნი არაა"
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr ""
+"პროგრამა „%s“ ნაპოვნია „%s“-ის მიერ, მაგრამ ვერსია, იგივეა არაა, რაც %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "სამიზნე კლასერში restore_command დაყენებული არაა"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "ავარიიდან სრულად აღდგენისთვის სამიზნე სერვერზე %s-ის შესრულდება"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "სამიზნე კლასტერში postgres-ის ერთმომხმარებლიანი რეჟიმის შეცდომა"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "ბრძანება იყო: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "სინტაქსის შეცდომა ისტორიის ფაილში: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "მოველოდი დროის ხაზის რიცხვობრივ ID-ს."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "მოველოდი წინასწარ-ჩაწერადი ჟურნალის გადართვის წერტილის მდებარეობას."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "არასწორი მონაცემები ისტორიის ფაილში \"%s\""
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "დროის ხაზის ID-ები ზრდადობით უნდა იყოს დალაგებული."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "არასწორი მონაცემები ისტორიის ფაილში"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "დროის ხაზის ID-ები შვილეული დროის ხაზის ID-ზე ნაკლები უნდა იყოს."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "ჩანაწერის არასწორი წანაცვლება მისამართზე %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "contrecord მოთხოვნილია %X/%X-ის მიერ"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "ჩანაწერის არასწორი სიგრძე მისამართზე %X/%X: მინდოდა %u, მივიღე %u"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "%u სიგრძის მქონე ჩანაწერის დეკოდირებისთვის მეხსიერება საკმარისი არაა"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "ჩანაწერის სიგრძე %u მისამართზე %X/%X ძალიან გრძელია"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "contrecord ალამი მისამართზე %X/%X არ არსებობს"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "contrecord -ის არასწორი სიგრძე %u (მოველოდი %lld) მისამართზე %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "contrecord მისამართზე %X/%X არ არსებობს"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "რესურსის მმართველის არასწორი ID %u მისამართზე %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "ჩანაწერი არასწორი წინა ბმულით %X/%X მისამართზე %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr ""
+"რესურსის მმართველის მონაცემების არასწორი საკონტროლო რიცხვი ჩანაწერში "
+"მისამართზე %X/%X"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "არასწორი მაგიური რიცხვი %04X ჟურნალის სეგმენტში %s, წანაცვლება %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "არასწორი საინფორმაციო ბიტები %04X ჟურნალის სეგმენტში %s, წანაცვლება %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid ""
+"WAL file is from different database system: WAL file database system "
+"identifier is %llu, pg_control database system identifier is %llu"
+msgstr ""
+"WAL ფაილი სხვა ბაზიდანაა: WAL ფაილის ბაზის იდენტიფიკატორია %llu, pg_control-"
+"ის ბაზის სისტემის იდენტიფიკატორი კი %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid ""
+"WAL file is from different database system: incorrect segment size in page "
+"header"
+msgstr ""
+"WAL ფაილი სხვა ბაზის სიტემიდანაა: სეგმანტის არასწორი ზომა გვერდის თავსართში"
+
+#: xlogreader.c:1274
+#, c-format
+msgid ""
+"WAL file is from different database system: incorrect XLOG_BLCKSZ in page "
+"header"
+msgstr ""
+"WAL ფაილი სხვა მონაცემთა ბაზის სისტემიდანაა: გვერდის თავსართში მითითებული "
+"XLOG_BLKSZ არასწორია"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "მოულოდნელი pageaddr %X/%X ჟურნალის სეგმენტში %s, წანაცვლება %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr ""
+"მიმდევრობის-გარე დროის ხაზის ID %u (%u-ის შემდეგ) ჟურნალის სეგმენტში %s, "
+"წანაცვლება %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "ურიგო block_id %u მისამართზე %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr ""
+"BKPBLOCK_HAS_DATA დაყენებულია, მაგრამ მონაცემები მისამართზე %X/%X არ არსებობს"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr ""
+"BKPBLOCK_HAS_DATA დაყენებულია, მაგრამ არსებობს მონაცემები სიგრძით %u "
+"მისამართზე %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid ""
+"BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at "
+"%X/%X"
+msgstr ""
+"BKPIMAGE_HAS_HOLE დაყენებულია, მაგრამ ნახვრეტის წანაცვლება %u სიგრძე %u "
+"ბლოკის ასლის სიგრძე %u მისამართზე %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr ""
+"BKPIMAGE_HAS_HOLE დაყენებული არაა, მაგრამ ნახვრეტის წანაცვლება %u სიგრძე %u "
+"მისანართზე %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr ""
+"BKPIMAGE_COMPRESSED დაყენებულია, მაგრამ ბლოკის ასლის სიგრძეა %u მისამართზე "
+"%X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid ""
+"neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image "
+"length is %u at %X/%X"
+msgstr ""
+"არც BKPIMAGE_HAS_HOLE და არც BKPIMAGE_COMPRESSED დაყენებული არაა, მაგრამ "
+"ბლოკის ასლის სიგრძე %u-ა, მისამართზე %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr ""
+"BKPBLOCK_SAME_REL დაყენებულია, მაგრამ წინა მნიშვნელობა მითითებული არაა "
+"მისამართზე %X/%X"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "არასწორი block_id %u %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "ჩანაწერი არასწორი სიგრძით მისამართზე %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "შეცდომა WAL ჩანაწერში მარქაფი ბლოკის, ID-ით %d, მოძებნისას"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr ""
+"შეუძლებელია ასლის აღდგენა მისამართზე %X/%X, როცა მითითებულია არასწორი ბლოკი "
+"%d"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr ""
+"შეუძლებელია ასლის აღდგენა მისამართზე %X/%X არასწორი მდგომარეობით, ბლოკი %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid ""
+"could not restore image at %X/%X compressed with %s not supported by build, "
+"block %d"
+msgstr ""
+"%3$s მეთოდით შეკუმშული ასლის აღდგენა მისამართზე %1$X/%2$X, ბლოკი %4$d "
+"შეუძლებელია. მხარდაუჭერელია ამ აგების მიერ"
+
+#: xlogreader.c:2111
+#, c-format
+msgid ""
+"could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr ""
+"შეუძლებელია ასლის აღდგენა მისამართზე %X/%X, შეკუმშულია უცნობი მეთოდით, ბლოკი "
+"%d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "შეუძლებელია ასლის გაშლა მისამართზე %X/%X, ბლოკი %d"
diff --git a/src/bin/pg_rewind/po/ko.po b/src/bin/pg_rewind/po/ko.po
new file mode 100644
index 0000000..d8ce7f0
--- /dev/null
+++ b/src/bin/pg_rewind/po/ko.po
@@ -0,0 +1,1073 @@
+# LANGUAGE message translation file for pg_rewind
+# Copyright (C) 2015 PostgreSQL Global Development Group
+# This file is distributed under the same license as the PostgreSQL package.
+# Ioseph Kim <ioseph@uri.sarang.net>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL) 15\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2023-04-12 00:50+0000\n"
+"PO-Revision-Date: 2023-04-05 18:07+0900\n"
+"Last-Translator: Ioseph Kim <ioseph@uri.sarang.net>\n"
+"Language-Team: Korean <pgsql-kr@postgresql.kr>\n"
+"Language: ko\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "오류: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "경고: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "상세정보: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "힌트: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "메모리 부족\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "null 포인터를 복제할 수 없음(내부 오류)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "\"%s\" 라이브러리를 불러 올 수 없음: 오류 코드 %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "이 운영체제에서 restricted 토큰을 만들 수 없음: 오류 코드 %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "프로세스 토큰을 열 수 없음: 오류 코드 %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "SID를 할당할 수 없음: 오류 코드 %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "restricted token을 만들 수 없음: 오류 코드 %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "\"%s\" 명령을 위한 프로세스를 시작할 수 없음: 오류 코드 %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "restricted token을 재실행 할 수 없음: 오류 코드 %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "하위 프로세스의 종료 코드를 구할 수 없음: 오류 코드 %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "%%r 치환문자열로 restore_command 사용할 수 없음"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "\"%s\" 파일 크기가 이상함: %lld 로 비정상, 정상값 %lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "아카이브에서 \"%s\" 파일 복원 실패: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "\"%s\" 파일의 상태값을 알 수 없음: %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "restore_command 실패: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "아카이브에서 \"%s\" 파일 복원 실패"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "메모리 부족"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "\"%s\" 파일을 열 수 없음: %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "\"%s\" 파일 쓰기 실패: %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "\"%s\" 파일을 만들 수 없음: %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "\"%s\" 대상 파일을 열 수 없음: %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "\"%s\" 대상 파일을 닫을 수 없음: %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "\"%s\" 대상 파일에서 seek 작업을 할 수 없음: %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "\"%s\" 파일 쓰기 실패: %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "알 수 없는 파일 포멧: \"%s\""
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "일반 파일에 대한 잘못 된 작업 (CREATE)"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "\"%s\" 파일을 삭제할 수 없음: %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "트랙잭션을 위한 \"%s\" 파일을 열 수 없음: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "\"%s\" 파일을 %u 크기로 정리할 수 없음: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "\"%s\" 디렉터리를 만들 수 없음: %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "\"%s\" 디렉터리를 삭제할 수 없음: %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "\"%s\"에 대한 심볼릭 링크를 만들 수 없음: %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "\"%s\" 심벌릭 링크를 삭제할 수 없음: %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "\"%s\" 파일 일기 모드로 열기 실패: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "\"%s\" 파일을 읽을 수 없음: %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "\"%s\" 파일을 읽을 수 없음: %d 읽음, 전체 %zu"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "\"%s\" 디렉터리 열 수 없음: %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "\"%s\" 심볼릭 링크 파일을 읽을 수 없음: %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "\"%s\" 심볼릭 링크의 대상이 너무 긺"
+
+#: file_ops.c:464
+#, c-format
+msgid ""
+"\"%s\" is a symbolic link, but symbolic links are not supported on this "
+"platform"
+msgstr ""
+"\"%s\" 파일은 심볼릭 링크 파일이지만 이 운영체제는 심볼릭 링크 파일을 지원하"
+"지 않음"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "\"%s\" 디렉터리를 읽을 수 없음: %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "\"%s\" 디렉터리를 닫을 수 없음: %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "\"%s\" 자료 파일은 일반 파일이 아님"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "\"%s\" 소스 파일을 두 번 지정했습니다"
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "\"%s\" 비일반 파일의 페이지 변경 정보가 잘못됨"
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "\"%s\" 파일 형식을 알 수 없음"
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "\"%s\" 파일 형식이 소스와 타켓이 서로 다름"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "\"%s\" 파일로 뭘 해야할지 결정할 수 없음"
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "search_path를 지울 수 없음: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "원본 서버는 full_page_writes 옵션으로 운영되어야 함"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "파일 내용을 뽑기 위한 구문을 준비할 수 없음: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "원본 서버에서 쿼리 (%s) 실행 오류: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "쿼리 결과가 바르지 않음"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "원본에서에서 쿼리(%s) 실행 오류: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "현재 WAL 삽입 위치를 위한 결과가 잘못됨 : \"%s\""
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "파일 목록을 가져올 수 없음: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "파일 목록을 가져온 결과가 잘못 됨"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "쿼리를 보낼 수 없음: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "libpq 연결을 단일 로우 모드로 지정할 수 없음"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "원격 파일을 가져오는 도중 결과가 잘못됨: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "용천 된 것보다 많은 데이터 청크를 받았음"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "원격 파일을 가져오는 도중 결과 집합의 크기가 잘못 됨"
+
+#: libpq_source.c:515
+#, c-format
+msgid ""
+"unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "원격 파일을 가져오는 도중 결과 집합의 자료형이 잘못 됨: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "원격 파일을 가져오는 중 예상치 못한 결과 형식 발견"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "원격 파일을 가져오는 도중 결과안에 null 값이 잘못됨"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "원격 파일을 가져오는 도중 결과 길이가 잘못됨"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "\"%s\" 파일용 데이터를 받았음, \"%s\" 요청 처리용"
+
+#: libpq_source.c:570
+#, c-format
+msgid ""
+"received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr ""
+"%lld 오프셋(해당파일: \"%s\")에 데이터를 받았음, %lld 오프셋 요청 처리용"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "\"%s\" 파일을 위한 보다 많은 요청을 받았음"
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "데이터 청크 수신 숫자가 이상함"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "\"%s\" 원격 파일을 가져올 수 없음: %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "\"%s\" 원격파일을 가져오는 도중 결과 집합이 잘못 됨"
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "\"%s\" 원본 파일을 열 수 없음: %m"
+
+#: local_source.c:117
+#, c-format
+msgid ""
+"size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "\"%s\" 소스 파일 크기가 현재 변경 되었음: 기대값: %d, 실재값 %d"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "\"%s\" 파일을 닫을 수 없음: %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "원본 파일에서 seek 작업을 할 수 없음: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "\"%s\" 파일을 읽는 중 예상치 못한 EOF"
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "WAL 읽기 프로세서를 할당하는 중 메모리 부족"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "%X/%X 위치에서 WAL 레코드를 읽을 수 없음: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "%X/%X 위치에서 WAL 레코드를 읽을 수 없음"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "%X/%X 끝 포인터는 바른값이 아님; 기대값: %X/%X"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "%X/%X 위치에서 이전 WAL 레코드를 찾을 수 없음: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "%X/%X 위치에서 이전 WAL 레코드를 찾을 수 없음"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "\"%s\" 파일에서 seek 작업을 할 수 없음: %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid ""
+"WAL record modifies a relation, but record type is not recognized: lsn: %X/"
+"%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr ""
+"WAL 레코드가 릴레이션을 변경하려고 하지만, 레코드 형태가 바르지 않음: lsn: "
+"%X/%X, rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s 프로그램은 PostgreSQL 한 클러스터에서 다른 클러스터로 재동기화 하는 도구입"
+"니다.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"사용법:\n"
+" %s [옵션]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "옵션들:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration "
+"to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal 아카이브에서 WAL 파일을 가져오기 위해\n"
+" 대상 환경 설정 restore_command 사용\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=디렉터리 변경하려는 데이터 디렉터리\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid ""
+" --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=디렉터리 동기화 원본이 되는 데이터 디렉터리\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=연결문자열 원본 서버 접속 정보\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run 변경 작업 전에 멈춤(검사, 확인용)\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr ""
+" -N, --no-sync 작업 완료 뒤 디스크 동기화 작업을 하지 않"
+"음\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress 진행 과정 메시지를 보여줌\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf 복제를 위한 환경 설정 함\n"
+" (--source-server 설정 필요함)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=파일이름 대상 클러스터를 실행할 때 사용할\n"
+" 서버 환경 설정 파일 지정\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug 디버그 메시지를 보여줌\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid ""
+" --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr ""
+" --no-ensure-shutdown 비정상 종료 시 자동 뒷정리 작업 안함\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid ""
+" -V, --version output version information, then exit\n"
+msgstr " -V, --version 버전 정보를 보여주고 마침\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help 이 도움말을 보여주고 마침\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"문제점 보고 주소: <%s>\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "%s 홈페이지: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "자세한 사항은 \"%s --help\" 명령으로 살펴보세요."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr ""
+"원본을 지정하지 않았음 (--source-pgdata 또는 --source-server 옵션을 지정 해"
+"야 함)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "--source-pgdata 또는 --source-server 옵션 중 하나만 지정해야 함"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "대상 데이터 디렉토리가 지정되지 않았음 (--target-pgdata 옵션 사용)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid ""
+"no source server information (--source-server) specified for --write-"
+"recovery-conf"
+msgstr "--write-recovery-conf 용 원보 서버 정보(--source-server) 없음"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "너무 많은 명령행 인수를 지정했습니다. (처음 \"%s\")"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "\"root\" 계정으로는 실행 할 수 없음"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "PostgreSQL superuser로 %s 프로그램을 실행하십시오."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "\"%s\" 디렉터리 읽기 권한 없음: %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "서버 접속 완료"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "원본과 대상 클러스터의 타임라인이 같음"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "서버 분기 WAL 위치: %X/%X, 타임라인 %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "되감을 필요 없음"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "재동기화 시작함, 마지막 체크포인트 위치 %X/%X, 타임라인 %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "원본 파일 목록 읽는 중"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "대상 파일 목록 읽는 중"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "대상 서버에서 WAL 읽는 중"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "복사를 위해서 %lu MB 필요함 (원본 디렉토리 전체 크기는 %lu MB)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "대상 데이터 디렉터리 동기화 중"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "완료!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "%s 외부 테이블 접근 권한 없음"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "pg_rewind 실행 되고 있는 중에 원본 시스템이 변경 되었음"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "백업 라벨을 만들고, 컨트롤 파일을 갱신 중"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "rewind 끝에 원본 시스템의 상태가 예상값과 다름"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "원본과 대상 클러스터가 서로 다른 시스템임"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "해당 클러스터는 이 pg_rewind 버전으로 작업할 수 없음"
+
+#: pg_rewind.c:703
+#, c-format
+msgid ""
+"target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr ""
+"대상 서버의 데이터 클러스터가 데이터 체크섬 기능을 켰거나, \"wal_log_hints "
+"= on\" 설정이 되어야 함"
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "대상 서버는 정상 종료되어야 함"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "원본 데이터 디렉토리는 정상적으로 종료되어야 함"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s kB (%d%%) 복사됨"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "잘못된 컨트롤 파일"
+
+#: pg_rewind.c:918
+#, c-format
+msgid ""
+"could not find common ancestor of the source and target cluster's timelines"
+msgstr "원본과 대상 서버의 공통된 상위 타임라인을 찾을 수 없음"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "백업 라벨 버퍼가 너무 작음"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "컨트롤 파일 CRC 오류"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "컨트롤 파일의 크기가 %d 로 비정상, 정상값 %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid ""
+"WAL segment size must be a power of two between 1 MB and 1 GB, but the "
+"control file specifies %d byte"
+msgid_plural ""
+"WAL segment size must be a power of two between 1 MB and 1 GB, but the "
+"control file specifies %d bytes"
+msgstr[0] ""
+"WAL 조각 파일은 1MB부터 1GB 사이 2^n 크기여야 하지만, 컨트롤 파일에는 %d 바이"
+"트로 지정되었음"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid ""
+"program \"%s\" is needed by %s but was not found in the same directory as "
+"\"%s\""
+msgstr ""
+"\"%s\" 프로그램이 %s 작업에서 필요합니다. 그런데, 이 파일이 \"%s\" 파일이 있"
+"는 디렉터리안에 없습니다."
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr ""
+"\"%s\" 프로그램을 \"%s\" 작업 때문에 찾았지만 이 파일은 %s 프로그램의 버전과 "
+"다릅니다."
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "대상 클러스터에 restore_command 설정이 없음"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "대상 서버에서 비정상 종료 후 복구 작업을 위해 \"%s\" 실행 중"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "대상 클러스터를 단일 사용자 모드로 postgres 실행 실패"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "사용된 명령: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "히스토리 파일에서 문법오류: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "숫자 타임라인 ID가 필요합니다."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "트랜잭션 로그 전환 위치 값이 있어야 함"
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "작업내역 파일에 잘못된 자료가 있음: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "타임라인 ID 값은 그 값이 증가하는 순번값이어야합니다."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "내역 파일에 잘못된 자료가 있음"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "타임라인 ID는 하위 타임라인 ID보다 작아야 합니다."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "잘못된 레코드 위치: %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "%X/%X에서 contrecord를 필요로 함"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "잘못된 레코드 길이: %X/%X, 기대값 %u, 실재값 %u"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "%u 길이의 레코드를 디코딩 하는 중 메모리 부족"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "너무 긴 길이(%u)의 레코드가 %X/%X에 있음"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "%X/%X 위치에 contrecord 플래그가 없음"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "잘못된 contrecord 길이 %u (기대값: %lld), 위치 %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "%X/%X 위치에 contrecord 없음"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "잘못된 자원 관리 ID %u, 위치: %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "레코드의 잘못된 프리링크 %X/%X, 해당 레코드 %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "잘못된 자원관리자 데이터 체크섬, 위치: %X/%X 레코드"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "%04X 매직 번호가 잘못됨, 로그 파일 %s, 위치 %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "잘못된 정보 비트 %04X, 로그 파일 %s, 위치 %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid ""
+"WAL file is from different database system: WAL file database system "
+"identifier is %llu, pg_control database system identifier is %llu"
+msgstr ""
+"WAL 파일이 다른 시스템의 것입니다. WAL 파일의 시스템 식별자는 %llu, "
+"pg_control 의 식별자는 %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid ""
+"WAL file is from different database system: incorrect segment size in page "
+"header"
+msgstr ""
+"WAL 파일이 다른 데이터베이스 시스템의 것입니다: 페이지 헤더에 지정된 값이 잘"
+"못된 조각 크기임"
+
+#: xlogreader.c:1274
+#, c-format
+msgid ""
+"WAL file is from different database system: incorrect XLOG_BLCKSZ in page "
+"header"
+msgstr ""
+"WAL 파일이 다른 데이터베이스 시스템의 것입니다: 페이지 헤더의 XLOG_BLCKSZ 값"
+"이 바르지 않음"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "잘못된 페이지 주소 %X/%X, 로그 파일 %s, 위치 %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "타임라인 범위 벗어남 %u (이전 번호 %u), 로그 파일 %s, 위치 %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "%u block_id는 범위를 벗어남, 위치 %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA 지정했지만, %X/%X 에 자료가 없음"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA 지정 않았지만, %u 길이의 자료가 있음, 위치 %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid ""
+"BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at "
+"%X/%X"
+msgstr ""
+"BKPIMAGE_HAS_HOLE 설정이 되어 있지만, 옵셋: %u, 길이: %u, 블록 이미지 길이: "
+"%u, 대상: %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr ""
+"BKPIMAGE_HAS_HOLE 설정이 안되어 있지만, 옵셋: %u, 길이: %u, 대상: %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr ""
+"BKPIMAGE_COMPRESSED 설정이 되어 있지만, 블록 이미지 길이: %u, 대상: %X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid ""
+"neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image "
+"length is %u at %X/%X"
+msgstr ""
+"BKPIMAGE_HAS_HOLE, BKPIMAGE_COMPRESSED 지정 안되어 있으나, 블록 이미지 길이"
+"는 %u, 대상: %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_REL 설정이 되어 있지만, %X/%X 에 이전 릴레이션 없음"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "잘못된 block_id %u, 위치 %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "잘못된 레코드 길이, 위치 %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "WAL 레코드에 %d ID 백업 블록이 없음"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "%X/%X 위치에 이미지 복원 실패(%d 블록이 바르지 않음)"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "%X/%X 에 잘못된 상태값으로 이미지 복원 실패, 블록 %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid ""
+"could not restore image at %X/%X compressed with %s not supported by build, "
+"block %d"
+msgstr ""
+"%X/%X 위치에 %s 압축된 이미지 복원 실패, 해당 엔진이 지원하지 않음, 해당블"
+"록: %d"
+
+#: xlogreader.c:2111
+#, c-format
+msgid ""
+"could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "%X/%X 위치에 알수 없는 압축 방식의 이미지 복원 실패, 해당블록: %d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "%X/%X 에서 이미 압축 풀기 실패, 블록 %d"
diff --git a/src/bin/pg_rewind/po/ru.po b/src/bin/pg_rewind/po/ru.po
new file mode 100644
index 0000000..f41d400
--- /dev/null
+++ b/src/bin/pg_rewind/po/ru.po
@@ -0,0 +1,1208 @@
+# Russian message translation file for pg_rewind
+# Copyright (C) 2015-2016 PostgreSQL Global Development Group
+# This file is distributed under the same license as the PostgreSQL package.
+# Alexander Lakhin <exclusion@gmail.com>, 2015-2017, 2018, 2019, 2020, 2021, 2022, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL current)\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2023-11-03 09:09+0300\n"
+"PO-Revision-Date: 2023-08-30 15:22+0300\n"
+"Last-Translator: Alexander Lakhin <exclusion@gmail.com>\n"
+"Language-Team: Russian <pgsql-ru-general@postgresql.org>\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
+"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "ошибка: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "предупреждение: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "подробности: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "подсказка: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "нехватка памяти\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "попытка дублирования нулевого указателя (внутренняя ошибка)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "не удалось загрузить библиотеку \"%s\" (код ошибки: %lu)"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "в этой ОС нельзя создавать ограниченные маркеры (код ошибки: %lu)"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "не удалось открыть маркер процесса (код ошибки: %lu)"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "не удалось подготовить структуры SID (код ошибки: %lu)"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "не удалось создать ограниченный маркер (код ошибки: %lu)"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "не удалось запустить процесс для команды \"%s\" (код ошибки: %lu)"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "не удалось перезапуститься с ограниченным маркером (код ошибки: %lu)"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "не удалось получить код выхода от подпроцесса (код ошибки: %lu)"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "нельзя использовать restore_command со знаком подстановки %%r"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "неподходящий размер файла \"%s\": %lld вместо %lld байт"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "не удалось открыть файл \"%s\", восстановленный из архива: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "не удалось получить информацию о файле \"%s\": %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "ошибка при выполнении restore_command: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "восстановить файл \"%s\" из архива не удалось"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "нехватка памяти"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "не удалось открыть файл \"%s\": %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "не удалось записать в файл \"%s\": %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "не удалось создать файл \"%s\": %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "не удалось открыть целевой файл \"%s\": %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "не удалось закрыть целевой файл \"%s\": %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "не удалось переместиться в целевом файле \"%s\": %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "не удалось записать файл \"%s\": %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "неопределённый тип файла \"%s\""
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "неверное действие (CREATE) для обычного файла"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "не удалось стереть файл \"%s\": %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "не удалось открыть файл \"%s\" для усечения: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "не удалось обрезать файл \"%s\" до нужного размера (%u): %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "не удалось создать каталог \"%s\": %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "ошибка при удалении каталога \"%s\": %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "не удалось создать символическую ссылку \"%s\": %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "ошибка при удалении символической ссылки \"%s\": %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "не удалось открыть файл \"%s\" для чтения: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "не удалось прочитать файл \"%s\": %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "не удалось прочитать файл \"%s\" (прочитано байт: %d из %zu)"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "не удалось открыть каталог \"%s\": %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "не удалось прочитать символическую ссылку \"%s\": %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "целевой путь символической ссылки \"%s\" слишком длинный"
+
+#: file_ops.c:464
+#, c-format
+msgid ""
+"\"%s\" is a symbolic link, but symbolic links are not supported on this "
+"platform"
+msgstr ""
+"\"%s\" — символическая ссылка, но в этой ОС символические ссылки не "
+"поддерживаются"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "не удалось прочитать каталог \"%s\": %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "не удалось закрыть каталог \"%s\": %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "файл данных \"%s\" в источнике не является обычным файлом"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "повторный исходный файл \"%s\""
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "неожиданная модификация страницы для файла особого вида \"%s\""
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "неизвестный тип файла \"%s\""
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "файл \"%s\" имеет разный тип в исходном и целевом кластере"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "не удалось определить, что делать с файлом \"%s\""
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "не удалось очистить search_path: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "на исходном сервере должен быть включён режим full_page_writes"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "не удалось подготовить оператор для извлечения содержимого файла: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "ошибка выполнения запроса (%s) на исходном сервере: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "неожиданный результат запроса"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "ошибка выполнения запроса (%s) на исходном сервере: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr ""
+"нераспознанный результат \"%s\" вместо текущей позиции добавления в WAL"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "не удалось получить список файлов: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "неожиданный результат при получении списка файлов"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "не удалось отправить запрос: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "не удалось перевести подключение libpq в однострочный режим"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "неожиданный результат при получении файлов с сервера: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "получено больше сегментов данных, чем запрошено"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "неожиданный размер набора результатов при получении файлов с сервера"
+
+#: libpq_source.c:515
+#, c-format
+msgid ""
+"unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr ""
+"неожиданные типы данных в наборе результатов при получении файлов с сервера: "
+"%u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "неожиданный формат результата при получении файлов с сервера"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "неожиданные значения NULL в результате при получении файлов с сервера"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "неожиданная длина результата при получении файлов с сервера"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "получены данные для файла \"%s\", а запрашивались данные для \"%s\""
+
+#: libpq_source.c:570
+#, c-format
+msgid ""
+"received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr ""
+"получены данные по смещению %lld в файле \"%s\", а запрашивались по смещению "
+"%lld"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "получено больше данных, чем запрошено для файла \"%s\""
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "получено неожиданное количество сегментов данных"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "не удалось получить с сервера файл \"%s\": %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "неожиданный набор результатов при получении файла \"%s\" с сервера"
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "не удалось открыть исходный файл \"%s\": %m"
+
+#: local_source.c:117
+#, c-format
+msgid ""
+"size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr ""
+"размер исходного файла \"%s\" изменился, ожидалось байт: %d, скопировано: %d"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "не удалось закрыть файл \"%s\": %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "не удалось переместиться в исходном файле: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "неожиданный конец файла при чтении \"%s\""
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "не удалось выделить память для чтения WAL"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "не удалось прочитать запись WAL в позиции %X/%X: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "не удалось прочитать запись WAL в позиции %X/%X"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr ""
+"конечный указатель %X/%X неверно задаёт конечную точку; ожидается %X/%X"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "не удалось найти предыдущую запись WAL в позиции %X/%X: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "не удалось найти предыдущую запись WAL в позиции %X/%X"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "не удалось переместиться в файле \"%s\": %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid ""
+"WAL record modifies a relation, but record type is not recognized: lsn: %X/"
+"%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr ""
+"Запись WAL модифицирует отношение, но тип записи не распознан: lsn: %X/%X, "
+"rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s синхронизирует кластер PostgreSQL с другой копией кластера.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"Использование:\n"
+" %s [ПАРАМЕТР]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "Параметры:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration "
+"to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal использовать для получения файлов WAL из\n"
+" архива команду restore_command из целевой\n"
+" конфигурации\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr ""
+" -D, --target-pgdata=КАТАЛОГ существующий каталог, куда будут записаны "
+"данные\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid ""
+" --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr ""
+" --source-pgdata=КАТАЛОГ исходный каталог, с которым будет проведена "
+"синхронизация\n"
+
+# well-spelled: ПОДКЛ
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr ""
+" --source-server=СТР_ПОДКЛ сервер, с которым будет проведена "
+"синхронизация\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr ""
+" -n, --dry-run остановиться до внесения каких-либо "
+"изменений\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr ""
+" -N, --no-sync не ждать завершения сохранения данных на "
+"диске\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress выводить сообщения о ходе процесса\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf записать конфигурацию для репликации\n"
+" (требуется указание --source-server)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=ИМЯ_ФАЙЛА использовать указанный основной файл\n"
+" конфигурации сервера при запуске целевого\n"
+" кластера\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr ""
+" --debug выдавать множество отладочных сообщений\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid ""
+" --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr ""
+" --no-ensure-shutdown не исправлять автоматически состояние,\n"
+" возникающее при нештатном отключении\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid ""
+" -V, --version output version information, then exit\n"
+msgstr " -V, --version показать версию и выйти\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help показать эту справку и выйти\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"Об ошибках сообщайте по адресу <%s>.\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "Домашняя страница %s: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "Для дополнительной информации попробуйте \"%s --help\"."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "источник не указан (требуется --source-pgdata или --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "указать можно только --source-pgdata либо --source-server"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "целевой каталог данных не указан (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid ""
+"no source server information (--source-server) specified for --write-"
+"recovery-conf"
+msgstr ""
+"отсутствует информация об исходном сервере (--source-server) для --write-"
+"recovery-conf"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "слишком много аргументов командной строки (первый: \"%s\")"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "программу не должен запускать root"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "Запускать %s нужно от имени суперпользователя PostgreSQL."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "не удалось считать права на каталог \"%s\": %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "подключение к серверу установлено"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "исходный и целевой кластер уже на одной линии времени"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "серверы разошлись в позиции WAL %X/%X на линии времени %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "перемотка не требуется"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr ""
+"перемотка от последней общей контрольной точки в позиции %X/%X на линии "
+"времени %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "чтение списка исходных файлов"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "чтение списка целевых файлов"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "чтение WAL в целевом кластере"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "требуется скопировать %lu МБ (общий размер исходного каталога: %lu МБ)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "синхронизация целевого каталога данных"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "Готово!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "действие не определено для файла \"%s\""
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "в исходной системе произошли изменения в процессе работы pg_rewind"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "создание метки копии и модификация управляющего файла"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "исходная система оказалась в неожиданном состоянии после перемотки"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "исходный и целевой кластеры относятся к разным системам"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "кластеры несовместимы с этой версией pg_rewind"
+
+#: pg_rewind.c:703
+#, c-format
+msgid ""
+"target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr ""
+"на целевом сервере должны быть контрольные суммы данных или \"wal_log_hints "
+"= on\""
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "целевой сервер должен быть выключен штатно"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "работа с исходным каталогом данных должна быть завершена штатно"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s КБ (%d%%) скопировано"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "неверный управляющий файл"
+
+#: pg_rewind.c:918
+#, c-format
+msgid ""
+"could not find common ancestor of the source and target cluster's timelines"
+msgstr ""
+"не удалось найти общего предка линий времени исходного и целевого кластеров"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "буфер для метки копии слишком мал"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "неверная контрольная сумма управляющего файла"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "неверный размер управляющего файла (%d), ожидалось: %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid ""
+"WAL segment size must be a power of two between 1 MB and 1 GB, but the "
+"control file specifies %d byte"
+msgid_plural ""
+"WAL segment size must be a power of two between 1 MB and 1 GB, but the "
+"control file specifies %d bytes"
+msgstr[0] ""
+"размер сегмента WAL должен задаваться степенью 2 в интервале от 1 МБ до 1 "
+"ГБ, но в управляющем файле указано значение: %d"
+msgstr[1] ""
+"Размер сегмента WAL должен задаваться степенью 2 в интервале от 1 МБ до 1 "
+"ГБ, но в управляющем файле указано значение: %d"
+msgstr[2] ""
+"Размер сегмента WAL должен задаваться степенью 2 в интервале от 1 МБ до 1 "
+"ГБ, но в управляющем файле указано значение: %d"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid ""
+"program \"%s\" is needed by %s but was not found in the same directory as "
+"\"%s\""
+msgstr "программа \"%s\" нужна для %s, но она не найдена в каталоге \"%s\""
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr ""
+"программа \"%s\" найдена программой \"%s\", но её версия отличается от "
+"версии %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "команда restore_command в целевом кластере не определена"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr ""
+"выполнение \"%s\" для восстановления согласованности на целевом сервере"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr ""
+"не удалось запустить postgres в целевом кластере в однопользовательском "
+"режиме"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "Выполнялась команда: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "синтаксическая ошибка в файле истории: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "Ожидается числовой идентификатор линии времени."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Ожидается положение точки переключения журнала предзаписи."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "неверные данные в файле истории: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "Идентификаторы линий времени должны возрастать."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "неверные данные в файле истории"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr ""
+"Идентификаторы линий времени должны быть меньше идентификатора линии-потомка."
+
+#: xlogreader.c:592
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "неверное смещение записи в позиции %X/%X"
+
+#: xlogreader.c:600
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "в позиции %X/%X запрошено продолжение записи"
+
+#: xlogreader.c:641 xlogreader.c:1106
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "неверная длина записи в позиции %X/%X: ожидалось %u, получено %u"
+
+#: xlogreader.c:730
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "нет флага contrecord в позиции %X/%X"
+
+#: xlogreader.c:743
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "неверная длина contrecord: %u (ожидалась %lld) в позиции %X/%X"
+
+#: xlogreader.c:1114
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "неверный ID менеджера ресурсов %u в позиции %X/%X"
+
+#: xlogreader.c:1127 xlogreader.c:1143
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "запись с неверной ссылкой назад %X/%X в позиции %X/%X"
+
+#: xlogreader.c:1181
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr ""
+"некорректная контрольная сумма данных менеджера ресурсов в записи в позиции "
+"%X/%X"
+
+#: xlogreader.c:1218
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "неверное магическое число %04X в сегменте журнала %s, смещение %u"
+
+#: xlogreader.c:1232 xlogreader.c:1273
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "неверные информационные биты %04X в сегменте журнала %s, смещение %u"
+
+#: xlogreader.c:1247
+#, c-format
+msgid ""
+"WAL file is from different database system: WAL file database system "
+"identifier is %llu, pg_control database system identifier is %llu"
+msgstr ""
+"файл WAL принадлежит другой СУБД: в нём указан идентификатор системы БД "
+"%llu, а идентификатор системы pg_control: %llu"
+
+#: xlogreader.c:1255
+#, c-format
+msgid ""
+"WAL file is from different database system: incorrect segment size in page "
+"header"
+msgstr ""
+"файл WAL принадлежит другой СУБД: некорректный размер сегмента в заголовке "
+"страницы"
+
+#: xlogreader.c:1261
+#, c-format
+msgid ""
+"WAL file is from different database system: incorrect XLOG_BLCKSZ in page "
+"header"
+msgstr ""
+"файл WAL принадлежит другой СУБД: некорректный XLOG_BLCKSZ в заголовке "
+"страницы"
+
+#: xlogreader.c:1292
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "неожиданный pageaddr %X/%X в сегменте журнала %s, смещение %u"
+
+#: xlogreader.c:1317
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr ""
+"нарушение последовательности ID линии времени %u (после %u) в сегменте "
+"журнала %s, смещение %u"
+
+#: xlogreader.c:1722
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "идентификатор блока %u идёт не по порядку в позиции %X/%X"
+
+#: xlogreader.c:1746
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA установлен, но данных в позиции %X/%X нет"
+
+#: xlogreader.c:1753
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr ""
+"BKPBLOCK_HAS_DATA не установлен, но длина данных равна %u в позиции %X/%X"
+
+#: xlogreader.c:1789
+#, c-format
+msgid ""
+"BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at "
+"%X/%X"
+msgstr ""
+"BKPIMAGE_HAS_HOLE установлен, но для пропуска заданы смещение %u и длина %u "
+"при длине образа блока %u в позиции %X/%X"
+
+#: xlogreader.c:1805
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr ""
+"BKPIMAGE_HAS_HOLE не установлен, но для пропуска заданы смещение %u и длина "
+"%u в позиции %X/%X"
+
+#: xlogreader.c:1819
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr ""
+"BKPIMAGE_COMPRESSED установлен, но длина образа блока равна %u в позиции %X/"
+"%X"
+
+#: xlogreader.c:1834
+#, c-format
+msgid ""
+"neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image "
+"length is %u at %X/%X"
+msgstr ""
+"ни BKPIMAGE_HAS_HOLE, ни BKPIMAGE_COMPRESSED не установлены, но длина образа "
+"блока равна %u в позиции %X/%X"
+
+#: xlogreader.c:1850
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr ""
+"BKPBLOCK_SAME_REL установлен, но предыдущее значение не задано в позиции %X/"
+"%X"
+
+#: xlogreader.c:1862
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "неверный идентификатор блока %u в позиции %X/%X"
+
+#: xlogreader.c:1929
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "запись с неверной длиной в позиции %X/%X"
+
+#: xlogreader.c:1954
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "не удалось найти копию блока с ID %d в записи журнала WAL"
+
+#: xlogreader.c:2038
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr ""
+"не удалось восстановить образ в позиции %X/%X с указанным неверным блоком %d"
+
+#: xlogreader.c:2045
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr ""
+"не удалось восстановить образ в позиции %X/%X с неверным состоянием, блок %d"
+
+#: xlogreader.c:2072 xlogreader.c:2089
+#, c-format
+msgid ""
+"could not restore image at %X/%X compressed with %s not supported by build, "
+"block %d"
+msgstr ""
+"не удалось восстановить образ в позиции %X/%X, сжатый методом %s, который не "
+"поддерживается этой сборкой, блок %d"
+
+#: xlogreader.c:2098
+#, c-format
+msgid ""
+"could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr ""
+"не удалось восстановить образ в позиции %X/%X, сжатый неизвестным методом, "
+"блок %d"
+
+#: xlogreader.c:2106
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "не удалось развернуть образ в позиции %X/%X, блок %d"
+
+#, c-format
+#~ msgid "out of memory while trying to decode a record of length %u"
+#~ msgstr "не удалось выделить память для декодирования записи длины %u"
+
+#, c-format
+#~ msgid "record length %u at %X/%X too long"
+#~ msgstr "длина записи %u в позиции %X/%X слишком велика"
+
+#, c-format
+#~ msgid "missing contrecord at %X/%X"
+#~ msgstr "нет записи contrecord в %X/%X"
+
+#~ msgid "fatal: "
+#~ msgstr "важно: "
+
+#~ msgid "\"%s\" is not a directory"
+#~ msgstr "\"%s\" не является каталогом"
+
+#~ msgid "\"%s\" is not a symbolic link"
+#~ msgstr "\"%s\" не является символической ссылкой"
+
+#~ msgid "\"%s\" is not a regular file"
+#~ msgstr "\"%s\" не является обычным файлом"
+
+#~ msgid "source file list is empty"
+#~ msgstr "список файлов в источнике пуст"
+
+#~ msgid "source server must not be in recovery mode"
+#~ msgstr "исходный сервер должен выйти из режима восстановления"
+
+#~ msgid "could not send COPY data: %s"
+#~ msgstr "не удалось отправить данные COPY: %s"
+
+#~ msgid "could not send file list: %s"
+#~ msgstr "не удалось отправить список файлов: %s"
+
+#~ msgid "could not send end-of-COPY: %s"
+#~ msgstr "не удалось отправить сообщение о завершении копирования: %s"
+
+#~ msgid "unexpected result while sending file list: %s"
+#~ msgstr "неожиданный результат при передаче списка: %s"
+
+#~ msgid "could not connect to server: %s"
+#~ msgstr "не удалось подключиться к серверу: %s"
+
+#~ msgid ""
+#~ "\n"
+#~ "Report bugs to <pgsql-bugs@lists.postgresql.org>.\n"
+#~ msgstr ""
+#~ "\n"
+#~ "Об ошибках сообщайте по адресу <pgsql-bugs@lists.postgresql.org>.\n"
+
+#~ msgid " block %u\n"
+#~ msgstr " блок %u\n"
+
+#~ msgid "entry \"%s\" excluded from source file list\n"
+#~ msgstr "\"%s\" исключён из списка исходных файлов\n"
+
+#~ msgid "entry \"%s\" excluded from target file list\n"
+#~ msgstr "\"%s\" исключён из списка целевых файлов\n"
+
+#~ msgid "%s (%s)\n"
+#~ msgstr "%s (%s)\n"
+
+#, fuzzy
+#~ msgid "could not set up connection context: %s"
+#~ msgstr "не удалось настроить контекст подключения: %s"
+
+#~ msgid "getting file chunks\n"
+#~ msgstr "получение сегментов файлов\n"
+
+#~ msgid ""
+#~ "received null value for chunk for file \"%s\", file has been deleted\n"
+#~ msgstr ""
+#~ "для файла \"%s\" вместо сегмента получено NULL-значение, файл удалён\n"
+
+#~ msgid "fetched file \"%s\", length %d\n"
+#~ msgstr "получен файл \"%s\", длина %d\n"
+
+#, fuzzy
+#~ msgid "could not create temporary table: %s"
+#~ msgstr "не удалось создать временную таблицу: %s"
+
+#~ msgid "Failure, exiting\n"
+#~ msgstr "Ошибка, выполняется выход\n"
+
+#~ msgid "could not read from file \"%s\": %s\n"
+#~ msgstr "не удалось прочитать файл \"%s\": %s\n"
+
+#~ msgid "Source timeline history:\n"
+#~ msgstr "История линии времени источника:\n"
+
+#~ msgid "Target timeline history:\n"
+#~ msgstr "История линии времени получателя:\n"
+
+#~ msgid "%d: %X/%X - %X/%X\n"
+#~ msgstr "%d: %X/%X - %X/%X\n"
+
+#~ msgid "sync of target directory failed\n"
+#~ msgstr "сбой синхронизации целевого каталога\n"
+
+#~ msgid ""
+#~ "WAL file is from different database system: incorrect XLOG_SEG_SIZE in "
+#~ "page header"
+#~ msgstr ""
+#~ "файл WAL принадлежит другой СУБД: некорректный XLOG_SEG_SIZE в заголовке "
+#~ "страницы"
diff --git a/src/bin/pg_rewind/po/sv.po b/src/bin/pg_rewind/po/sv.po
new file mode 100644
index 0000000..d283f81
--- /dev/null
+++ b/src/bin/pg_rewind/po/sv.po
@@ -0,0 +1,1010 @@
+# Swedish message translation file for pg_rewind
+# Copyright (C) 2017 PostgreSQL Global Development Group
+# This file is distributed under the same license as the PostgreSQL package.
+# Dennis Björklund <db@zigo.dhs.org>, 2017, 2018, 2019, 2020, 2021, 2022.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PostgreSQL 15\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2022-09-29 11:51+0000\n"
+"PO-Revision-Date: 2022-09-29 21:42+0200\n"
+"Last-Translator: Dennis Björklund <db@zigo.dhs.org>\n"
+"Language-Team: Swedish <pgsql-translators@postgresql.org>\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "fel: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "varning: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "detalj: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "tips: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "slut på minne\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "kan inte duplicera null-pekare (internt fel)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "kunde inte ladda länkbibliotek \"%s\": felkod %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "kan inte skapa token för begränsad åtkomst på denna plattorm: felkod %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "kunde inte öppna process-token: felkod %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "kunde inte allokera SID: felkod %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "kunde inte skapa token för begränsad åtkomst: felkod %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "kunde inte starta process för kommando \"%s\": felkod %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "kunde inte köra igen med token för begränsad åtkomst: felkod %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "kunde inte hämta statuskod för underprocess: felkod %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "kan inte använda restore_command med %%r-platshållare"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "oväntad filstorlek på \"%s\": %lld istället för %lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "kunde inte öppna fil \"%s\" återställd från arkiv: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "kunde inte göra stat() på fil \"%s\": %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "restore_command misslyckades: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "kunde inte återställa fil \"%s\" från arkiv"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "slut på minne"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "kunde inte öppna fil \"%s\": %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "kunde inte skriva till fil \"%s\": %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "kan inte skapa fil \"%s\": %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "kunde inte öppna målfil \"%s\": %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "kunde inte stänga målfil \"%s\": %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "kunde inte söka i målfil \"%s\": %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "kunde inte skriva fil \"%s\": %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "odefinierad filtyp på \"%s\""
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "ogiltig aktion (CREATE) för vanlig fil"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "kunde inte ta bort fil \"%s\": %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "kunde inte öppna fil \"%s\" för trunkering: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "kunde inte trunkera fil \"%s\" till %u: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "kunde inte skapa katalog \"%s\": %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "kunde inte ta bort katalog \"%s\": %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "kunde inte skapa en symnbolisk länk vid \"%s\": %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "kan inte ta bort symbolisk länk \"%s\": %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "kunde inte öppna filen \"%s\" för läsning: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "kunde inte läsa fil \"%s\": %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "kunde inte läsa fil \"%s\": läste %d av %zu"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "kunde inte öppna katalog \"%s\": %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "kan inte läsa symbolisk länk \"%s\": %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "mål för symbolisk länk \"%s\" är för lång"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "\"%s\" är en symbolisk länk men symboliska länkar stöds inte på denna plattform"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "kunde inte läsa katalog \"%s\": %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "kunde inte stänga katalog \"%s\": %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "datafil \"%s\" i källan är inte en vanlig fil"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "duplicerad källflagga \"%s\""
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "oväntad sidmodifiering för icke-regulär fil \"%s\""
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "okänd filtyp på \"%s\""
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "filen \"%s\" har olika typ i källa och mål"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "kunde inte bestämma vad som skulle göras med filen \"%s\""
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "kunde inte nollställa search_path: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "full_page_writes måste vara påslagen i källservern"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "kunde inte förbereda satsen för att hämta filinnehåll: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "fel vid körande av fråga (%s) på källserver: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "oväntad resultatmängd från fråga"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "fel vid körande av fråga (%s) i källserver: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "oväntat resultat \"%s\" för nuvarande WAL-insättningsposition"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "kunde inte hämta fillista: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "oväntad resultatmängd vid hämtning av fillista"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "kunde inte skicka fråga: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "kunde inte sätta libpq-anslutning till enradsläge"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "oväntat resultat vid hämtning av extern fil: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "tog emot fler datastycken än efterfrågat"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "oväntad resultatmängdstorlek vid hämtning av externa filer"
+
+#: libpq_source.c:515
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "oväntade datayper i resultatmängd vid hämtning av externa filer: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "oväntat resultatformat vid hämtning av externa filer"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "oväntade null-värden i resultat vid hämtning av externa filer"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "oväntad resultatlängd vid hämtning av externa filer"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "fick data för filen \"%s\", men efterfrågade för \"%s\""
+
+#: libpq_source.c:570
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "fick data från offset %lld i fil \"%s\", men efterfrågade offset %lld"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "tog emot mer än efterfrågat för filen \"%s\""
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "oväntat antal datastycken togs emot"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "kunde inte hämta extern fil \"%s\": %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "oväntat resultatmängd vid hämtning av extern fil \"%s\""
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "kunde inte öppna källfil \"%s\": %m"
+
+#: local_source.c:117
+#, c-format
+msgid "size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "storleken på källfilen \"%s\" ändrades under körning: %d byte förväntades, %d kopierades"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "kunde inte stänga fil \"%s\": %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "kunde inte söka i källfil: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "oväntad EOF under läsning av fil \"%s\""
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "slut på minne vid allokering av en WAL-läs-processor"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "kunde inte läsa WAL-post vid %X/%X: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "kunde inte läsa WAL-post vid %X/%X"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "slutpekare %X/%X är inte en giltig slutposition; förväntade %X/%X"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "kunde inte hitta föregående WAL-post vid %X/%X: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "kunde inte hitta förgående WAL-post vid %X/%X"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "kunde inte söka (seek) i fil \"%s\": %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr "WAL-post modifierar en relation, men posttypen känns inte igen: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s resynkroniserar ett PostgreSQL-kluster med en annan kopia av klustret.\n"
+"\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"Användning:\n"
+" %s [FLAGGA]...\n"
+"\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "Flaggor:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal använd restore_command i målkonfigurationen\n"
+" för att hämta WAL-filer från arkiv\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=KATALOG existerande datakatalog att modifiera\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=KATALOG källdatakatalog att synkronisera med\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=ANSLSTR källserver att synkronisera med\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run stoppa innan något modifieras\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr ""
+" -N, --no-sync vänta inte på att ändingar säkert\n"
+" skrivits till disk\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress skriv ut förloppmeddelanden\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf\n"
+" skriv konfiguration för replikering\n"
+" (kräver --source-server)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid ""
+" --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr ""
+" --config-file=FILNAMN använd angiven serverkonfiguration när\n"
+" målklustret körs\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug skriv ut en massa debugmeddelanden\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr " --no-ensure-shutdown ingen automatisk hantering av trasig nedstängning\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version skriv ut versioninformation och avsluta sedan\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help visa denna hjälp och avsluta sedan\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"Rapportera fel till <%s>.\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "hemsida för %s: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "Försök med \"%s --help\" för mer information."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "ingen källa angavs (--source-pgdata eller --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "bara en av --source-pgdata och --source-server får anges"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "ingen måldatakatalog angiven (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "ingen källserverinformation (--source-server) angiven för --write-recovery-conf"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "för många kommandoradsargument (första är \"%s\")"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "kan inte köras av \"root\""
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "Du måste köra %s som PostgreSQL:s superuser."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "kunde inte läsa rättigheter på katalog \"%s\": %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "ansluten till server"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "källa och målkluster är på samma tidslinje"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "servrarna divergerade vid WAL-position %X/%X på tidslinje %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "ingen rewind krävs"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "rewind från senaste gemensamma checkpoint vid %X/%X på tidslinje %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "läser källfillista"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "läser målfillista"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "läser WAL i målet"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "behöver kopiera %lu MB (total källkatalogstorlek är %lu MB)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "synkar måldatakatalog"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "Klar!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "ingen åtgärd beslutades för filen \"%s\""
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "källsystemet ändrades samtidigt som pg_rewind kördes"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "skapar backupetikett och uppdaterar kontrollfil"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "källsystemet var i ett oväntat tillstånd vid slutet av återspolningen"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "källa och målkluster är från olika system"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "klustren är inte kompatibla med denna version av pg_rewind"
+
+#: pg_rewind.c:703
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "målservern behöver använda antingen datachecksums eller \"wal_log_hints = on\""
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "målserver måste stängas ner utan fel"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "måldatakatalog måste stängas ner utan fel"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "%*s/%s kB (%d%%) kopierad"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "ogiltig kontrollfil"
+
+#: pg_rewind.c:918
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "kunde inte finna en gemensam anfader av källa och målklusterets tidslinjer"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "backupetikett-buffer för liten"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "oväntad kontrollfil-CRC"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "oväntad kontrollfilstorlek %d, förväntade %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "WAL-segmentstorlek måste vara en tvåpotens mellan 1MB och 1GB men kontrollfilen anger %d byte"
+msgstr[1] "WAL-segmentstorlek måste vara en tvåpotens mellan 1MB och 1GB men kontrollfilen anger %d byte"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid "program \"%s\" is needed by %s but was not found in the same directory as \"%s\""
+msgstr "programmet \"%s\" behövs av %s men hittades inte i samma katalog som \"%s\""
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr "programmet \"%s\" hittades av \"%s\" men är inte av samma version som %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "restore_command är inte satt i målklustret"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "kör \"%s\" för målservern för att slutföra krashåterställning"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "postgres enanvändarläge misslyckades i målklustret"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "Kommandot var: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "syntaxfel i history-fil: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "Förväntade ett numeriskt tidslinje-ID."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Förväntade en write-ahead-logg:s switchpoint-position."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "felaktig data i history-fil: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "Tidslinje-ID måste komma i en stigande sekvens."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "ogiltig data i historikfil"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "Tidslinje-ID:er måste vara mindre än barnens tidslinje-ID:er."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "ogiltig postoffset vid %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "contrecord är begärd vid %X/%X"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "ogiltig postlängd vid %X/%X: förväntade %u, fick %u"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "slut på minne vid avkodning av post med längden %u"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "postlängd %u vid %X/%X är för lång"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "det finns ingen contrecord-flagga vid %X/%X"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "ogiltig contrecord-längd %u (förväntade %lld) vid %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "det finns ingen contrecord vid %X/%X"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "ogiltigt resurshanterar-ID %u vid %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "post med inkorrekt prev-link %X/%X vid %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "felaktig resurshanterardatakontrollsumma i post vid %X/%X"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "felaktigt magiskt nummer %04X i loggsegment %s, offset %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "ogiltiga infobitar %04X i loggsegment %s, offset %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "WAL-fil är från ett annat databassystem: WAL-filens databassystemidentifierare är %llu, pg_control databassystemidentifierare är %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "WAL-fil är från ett annat databassystem: inkorrekt segmentstorlek i sidhuvud"
+
+#: xlogreader.c:1274
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "WAL-fil är från ett annat databassystem: inkorrekt XLOG_BLCKSZ i sidhuvud"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "oväntad sidadress %X/%X i loggsegment %s, offset %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "ej-i-sekvens för tidslinje-ID %u (efter %u) i loggsegment %s, offset %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "ej-i-sekvens block_id %u vid %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA satt, men ingen data inkluderad vid %X/%X"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA ej satt, men datalängd är %u vid %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE satt, men håloffset %u längd %u block-image-längd %u vid %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE ej satt, men håloffset %u längd %u vid %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_COMPRESSED satt, men blockavbildlängd %u vid %X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "varken BKPIMAGE_HAS_HOLE eller BKPIMAGE_COMPRESSED satt, men blockavbildlängd är %u vid %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_REL satt men ingen tidigare rel vid %X/%X"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "ogiltig block_id %u vid %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "post med ogiltig längd vid %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "kunde inte hitta backup-block med ID %d i WAL-post"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "kunde inte återställa avbild vid %X/%X med ogiltigt block %d angivet"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "kunde inte återställa avbild vid %X/%X med ogiltigt state, block %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid "could not restore image at %X/%X compressed with %s not supported by build, block %d"
+msgstr "kunde inte återställa avbild vid %X/%X komprimerade med %s stöds inte av bygget, block %d"
+
+#: xlogreader.c:2111
+#, c-format
+msgid "could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "kunde inte återställa avbild vid %X/%X komprimerad med okänd metod, block %d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "kunde inte packa upp avbild vid %X/%X, block %d"
diff --git a/src/bin/pg_rewind/po/uk.po b/src/bin/pg_rewind/po/uk.po
new file mode 100644
index 0000000..4c0357f
--- /dev/null
+++ b/src/bin/pg_rewind/po/uk.po
@@ -0,0 +1,993 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: postgresql\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2023-01-31 23:20+0000\n"
+"PO-Revision-Date: 2023-04-19 15:06\n"
+"Last-Translator: \n"
+"Language-Team: Ukrainian\n"
+"Language: uk_UA\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=4; plural=((n%10==1 && n%100!=11) ? 0 : ((n%10 >= 2 && n%10 <=4 && (n%100 < 12 || n%100 > 14)) ? 1 : ((n%10 == 0 || (n%10 >= 5 && n%10 <=9)) || (n%100 >= 11 && n%100 <= 14)) ? 2 : 3));\n"
+"X-Crowdin-Project: postgresql\n"
+"X-Crowdin-Project-ID: 324573\n"
+"X-Crowdin-Language: uk\n"
+"X-Crowdin-File: /REL_15_STABLE/pg_rewind.pot\n"
+"X-Crowdin-File-ID: 908\n"
+
+#: ../../../src/common/logging.c:276
+#, c-format
+msgid "error: "
+msgstr "помилка: "
+
+#: ../../../src/common/logging.c:283
+#, c-format
+msgid "warning: "
+msgstr "попередження: "
+
+#: ../../../src/common/logging.c:294
+#, c-format
+msgid "detail: "
+msgstr "деталі: "
+
+#: ../../../src/common/logging.c:301
+#, c-format
+msgid "hint: "
+msgstr "підказка: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "недостатньо пам'яті\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "неможливо дублювати нульовий покажчик (внутрішня помилка)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "не вдалося завантажити бібліотеку \"%s\": код помилки %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "не вдалося створити обмежені токени на цій платформі: код помилки %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "не вдалося відкрити токен процесу: код помилки %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "не вдалося виділити SID: код помилки %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "не вдалося створити обмежений токен: код помилки %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "не вдалося запустити процес для команди \"%s\": код помилки %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "не вдалося перезапустити з обмеженим токеном: код помилки %lu"
+
+#: ../../common/restricted_token.c:193
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "не вдалося отримати код завершення підпроцесу: код помилки %lu"
+
+#: ../../fe_utils/archive.c:52
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "не вдалося використати restore_command із заповнювачем %%r"
+
+#: ../../fe_utils/archive.c:70
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "неочікуваний розмір файлу для \"%s\": %lld замість %lld"
+
+#: ../../fe_utils/archive.c:78
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "не вдалося відкрити файл \"%s\" відновлений з архіву: %m"
+
+#: ../../fe_utils/archive.c:87 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "не вдалося отримати інформацію від файлу \"%s\": %m"
+
+#: ../../fe_utils/archive.c:99
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "помилка restore_command: %s"
+
+#: ../../fe_utils/archive.c:106
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "не вдалося відновити файл \"%s\" з архіву"
+
+#: ../../fe_utils/recovery_gen.c:34 ../../fe_utils/recovery_gen.c:45
+#: ../../fe_utils/recovery_gen.c:70 ../../fe_utils/recovery_gen.c:90
+#: ../../fe_utils/recovery_gen.c:149
+#, c-format
+msgid "out of memory"
+msgstr "недостатньо пам'яті"
+
+#: ../../fe_utils/recovery_gen.c:121 parsexlog.c:312
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "не можливо відкрити файл \"%s\": %m"
+
+#: ../../fe_utils/recovery_gen.c:124
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "неможливо записати до файлу \"%s\": %m"
+
+#: ../../fe_utils/recovery_gen.c:133
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "неможливо створити файл \"%s\": %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "не вдалося відкрити цільовий файл \"%s\": %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "не вдалося закрити цільовий файл \"%s\": %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "не вдалося знайти в цільовому файлі \"%s\": %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "не вдалося записати файл \"%s\": %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "невизначений тип файлу для \"%s\""
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "неприпустима дія (CREATE) для звичайного файлу"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "не можливо видалити файл \"%s\": %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "не вдалося відкрити файл \"%s\" для скорочення: %m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "не вдалося скоротити файл \"%s\" до потрібного розміру %u: %m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "не вдалося створити каталог \"%s\": %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "не вдалося видалити каталог \"%s\": %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "неможливо створити символічне послання на \"%s\": %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "не вдалося видалити символьне посилання \"%s\": %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "не вдалося відкрити файл \"%s\" для читання: %m"
+
+#: file_ops.c:341 local_source.c:104 local_source.c:163 parsexlog.c:350
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "не вдалося прочитати файл \"%s\": %m"
+
+#: file_ops.c:344 parsexlog.c:352
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "не вдалося прочитати файл \"%s\": прочитано %d з %zu"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "не вдалося відкрити каталог \"%s\": %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "не можливо прочитати символічне послання \"%s\": %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "таргет символічного посилання \"%s\" задовгий"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "\"%s\"є символічним посиланням, але символічні посилання не підтримуються на даній платформі"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "не вдалося прочитати каталог \"%s\": %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "не вдалося закрити каталог \"%s\": %m"
+
+#: filemap.c:236
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "файл даних \"%s\" в джерелі не є регулярним файлом"
+
+#: filemap.c:241 filemap.c:274
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "дублікат вихідного файлу \"%s\""
+
+#: filemap.c:329
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "неочікувана модифікація сторінки для нерегулярного файлу \"%s\""
+
+#: filemap.c:679 filemap.c:773
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "невідомий тип файлу для \"%s\""
+
+#: filemap.c:706
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "файл \"%s\" має різні типи у джерелі та цілі"
+
+#: filemap.c:778
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "не вдалося вирішити, що робити з файлом \"%s\""
+
+#: libpq_source.c:130
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "не вдалося очистити search_path: %s"
+
+#: libpq_source.c:141
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "на початковому сервері повинно бути увімкнено full_page_writes"
+
+#: libpq_source.c:152
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "не вдалося підготувати інструкцію щоб отримати вміст файлу: %s"
+
+#: libpq_source.c:171
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "помилка при виконанні запиту (%s) на вихідному сервері: %s"
+
+#: libpq_source.c:176
+#, c-format
+msgid "unexpected result set from query"
+msgstr "неочікуваний результат запиту"
+
+#: libpq_source.c:198
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "помилка при виконанні запиту (%s) на початковому сервері: %s"
+
+#: libpq_source.c:219
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "нерозпізнаний результат \"%s\" замість поточної добавленої позиції WAL"
+
+#: libpq_source.c:270
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "не вдалося отримати список файлів: %s"
+
+#: libpq_source.c:275
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "неочікуваний результат при отриманні списку файлів"
+
+#: libpq_source.c:467
+#, c-format
+msgid "could not send query: %s"
+msgstr "не вдалося надіслати запит: %s"
+
+#: libpq_source.c:470
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "не вдалося встановити libpq з'єднання для однорядкового режиму"
+
+#: libpq_source.c:500
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "неочікуваний результат при отриманні віддалених файлів: %s"
+
+#: libpq_source.c:505
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "отримано більше фрагментів даних, ніж запитувалось"
+
+#: libpq_source.c:509
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "неочікуваний розмір набору результатів при отриманні віддалених файлів"
+
+#: libpq_source.c:515
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "неочікувані типи даних в результаті при отриманні віддалених файлів: %u %u %u"
+
+#: libpq_source.c:523
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "неочікуваний формат результату при отриманні віддалених файлів"
+
+#: libpq_source.c:529
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "неочікувані нульові значення в результаті при отриманні віддалених файлів"
+
+#: libpq_source.c:533
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "неочікувана довжина результату при отриманні віддалених файлів"
+
+#: libpq_source.c:566
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "отримані дані для файлу \"%s\", коли запитувалось для \"%s\""
+
+#: libpq_source.c:570
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "отримано дані по зсуву %lld файлу \"%s\", коли запитувалось про зсув %lld"
+
+#: libpq_source.c:582
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "отримано більше, ніж запитувалось для файлу \"%s\""
+
+#: libpq_source.c:595
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "отримано неочікувану кількість фрагментів даних"
+
+#: libpq_source.c:638
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "не вдалося отримати віддалений файл \"%s\": %s"
+
+#: libpq_source.c:643
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "неочікуваний набір результатів при отриманні віддаленого файлу \"%s\""
+
+#: local_source.c:90 local_source.c:142
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "не вдалося відкрити вихідний файл \"%s\": %m"
+
+#: local_source.c:117
+#, c-format
+msgid "size of source file \"%s\" changed concurrently: %d bytes expected, %d copied"
+msgstr "розмір вихідного файлу \"%s\" паралельно змінився: очікувалося %d байт, %d скопійовано"
+
+#: local_source.c:121 local_source.c:172
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "неможливо закрити файл \"%s\": %m"
+
+#: local_source.c:146
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "не вдалося знайти у вихідному файлі: %m"
+
+#: local_source.c:165
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "неочікуваний кінець при читанні файлу \"%s\""
+
+#: parsexlog.c:80 parsexlog.c:139 parsexlog.c:199
+#, c-format
+msgid "out of memory while allocating a WAL reading processor"
+msgstr "недостатньо пам'яті під час виділення обробника читання WAL"
+
+#: parsexlog.c:92 parsexlog.c:146
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "не вдалося прочитати запис WAL на %X/%X: %s"
+
+#: parsexlog.c:96 parsexlog.c:149
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "не вдалося прочитати запис WAL на %X/%X"
+
+#: parsexlog.c:108
+#, c-format
+msgid "end pointer %X/%X is not a valid end point; expected %X/%X"
+msgstr "кінцевий покажчик %X/%X не є допустимою кінцевою точкою; очікувалось %X/%X"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "не вдалося знайти попередній запис WAL на %X/%X: %s"
+
+#: parsexlog.c:216
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "не вдалося знайти попередній запис WAL на %X/%X"
+
+#: parsexlog.c:341
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "не вдалося знайти в файлі \"%s\": %m"
+
+#: parsexlog.c:440
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+msgstr "WAL модифікує відношення, але тип запису не розпізнано: lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:86
+#, c-format
+msgid "%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"
+msgstr "%s синхронізує кластер PostgreSQL з іншою копією кластеру.\n\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid "Usage:\n"
+" %s [OPTION]...\n\n"
+msgstr "Використання:\n"
+" %s [OPTION]...\n\n"
+
+#: pg_rewind.c:88
+#, c-format
+msgid "Options:\n"
+msgstr "Параметри:\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid " -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr " -c, --restore-target-wal використовує restore_command в цільовій конфігурації, щоб\n"
+" отримати файли WAL з архівів\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=DIRECTORY існуючий каталог для змін\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=DIRECTORY початковий каталог даних для синхронізації\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=CONNSTR початковий сервер для синхронізації\n"
+
+#: pg_rewind.c:94
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run зупинитися до внесення будь-яких змін\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid " -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr " -N, --no-sync не чекати поки зміни будуть записані на диск\n"
+
+#: pg_rewind.c:97
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress повідомляти про хід процесу\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid " -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr " -R, --write-recovery-conf записує конфігурацію для реплікації \n"
+" (потребує --source-server)\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid " --config-file=FILENAME use specified main server configuration\n"
+" file when running target cluster\n"
+msgstr " --config-file=FILENAME використовувати заданий основний файл конфігурації сервера\n"
+" при запуску цільового кластера\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug виводити багато налагоджувальних повідомлень\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr " --no-ensure-shutdown не виправляти автоматично неочищене завершення роботи\n"
+
+#: pg_rewind.c:104
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version вивести інформацію про версію і вийти\n"
+
+#: pg_rewind.c:105
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help показати довідку, потім вийти\n"
+
+#: pg_rewind.c:106
+#, c-format
+msgid "\n"
+"Report bugs to <%s>.\n"
+msgstr "\n"
+"Повідомляти про помилки на <%s>.\n"
+
+#: pg_rewind.c:107
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "Домашня сторінка %s: <%s>\n"
+
+#: pg_rewind.c:215 pg_rewind.c:223 pg_rewind.c:230 pg_rewind.c:237
+#: pg_rewind.c:244 pg_rewind.c:252
+#, c-format
+msgid "Try \"%s --help\" for more information."
+msgstr "Спробуйте \"%s --help\" для додаткової інформації."
+
+#: pg_rewind.c:222
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "джерело не вказано (--source-pgdata чи --source-server)"
+
+#: pg_rewind.c:229
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "може бути вказано лише --source-pgdata чи --source-server"
+
+#: pg_rewind.c:236
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "не вказано жодного каталогу цільових даних (--target-pgdata)"
+
+#: pg_rewind.c:243
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "немає інформації про вихідний сервер (--source-server) вказаної для --write-recovery-conf"
+
+#: pg_rewind.c:250
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "забагато аргументів у командному рядку (перший \"%s\")"
+
+#: pg_rewind.c:265
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "\"root\" не може це виконувати"
+
+#: pg_rewind.c:266
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser."
+msgstr "Запускати %s треба від суперкористувача PostgreSQL."
+
+#: pg_rewind.c:276
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "не вдалося прочитати дозволи на каталог \"%s\": %m"
+
+#: pg_rewind.c:294
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:297
+#, c-format
+msgid "connected to server"
+msgstr "під'єднано до серверу"
+
+#: pg_rewind.c:344
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "початковий і цільовий кластери знаходяться на одній лінії часу"
+
+#: pg_rewind.c:353
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "сервери розійшлись в позиції WAL %X/%X на лінії часу %u"
+
+#: pg_rewind.c:401
+#, c-format
+msgid "no rewind required"
+msgstr "перемотування не потрібне"
+
+#: pg_rewind.c:410
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "перемотування від останньої спільної контрольної точки на %X/%X на лінії часу %u"
+
+#: pg_rewind.c:420
+#, c-format
+msgid "reading source file list"
+msgstr "читання списку файлів із джерела"
+
+#: pg_rewind.c:424
+#, c-format
+msgid "reading target file list"
+msgstr "читання списку цільових файлів"
+
+#: pg_rewind.c:433
+#, c-format
+msgid "reading WAL in target"
+msgstr "читання WAL у цілі"
+
+#: pg_rewind.c:454
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "треба скопіювати %lu МБ (загальний розмір каталогу джерела становить %lu МБ)"
+
+#: pg_rewind.c:472
+#, c-format
+msgid "syncing target data directory"
+msgstr "синхронізація цільового каталогу даних"
+
+#: pg_rewind.c:488
+#, c-format
+msgid "Done!"
+msgstr "Готово!"
+
+#: pg_rewind.c:568
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "жодних дій щодо файлу \"%s\" не прийнято"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "вихідну систему було змінено під час роботи pg_rewind"
+
+#: pg_rewind.c:604
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "створення мітки резервного копіювання і оновлення контрольного файлу"
+
+#: pg_rewind.c:654
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "вихідна система була в неочікуваному стані наприкінці перемотування"
+
+#: pg_rewind.c:685
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "початковий і цільовий кластер належать до різних систем"
+
+#: pg_rewind.c:693
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "кластери не сумісні з даною версією pg_rewind"
+
+#: pg_rewind.c:703
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "цільовий сервер потребує використання контрольної суми даних або \"wal_log_hints = on\""
+
+#: pg_rewind.c:714
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "цільовий сервер повинен бути вимкненим штатно"
+
+#: pg_rewind.c:724
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "робота з початковим каталогом даних повинна бути завершена штатно"
+
+#: pg_rewind.c:771
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "скопійовано %*s/%s кБ (%d%%)"
+
+#: pg_rewind.c:834
+#, c-format
+msgid "invalid control file"
+msgstr "неприпустимий контрольний файл"
+
+#: pg_rewind.c:918
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "не вдалося знайти спільного предка ліній часу початкового та цільового кластерів"
+
+#: pg_rewind.c:959
+#, c-format
+msgid "backup label buffer too small"
+msgstr "буфер для мітки резервного копіювання замалий"
+
+#: pg_rewind.c:982
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "неочікуваний контрольний файл CRC"
+
+#: pg_rewind.c:994
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "неочікуваний розмір контрольного файлу %d, очікувалося %d"
+
+#: pg_rewind.c:1003
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "Розмір сегменту WAL повинен задаватись ступенем 2 в інтервалі від 1 МБ до 1 ГБ, але в керуючому файлі вказано значення %d"
+msgstr[1] "Розмір сегменту WAL повинен задаватись ступенем 2 в інтервалі від 1 МБ до 1 ГБ, але в керуючому файлі вказано значення %d"
+msgstr[2] "Розмір сегменту WAL повинен задаватись ступенем 2 в інтервалі від 1 МБ до 1 ГБ, але в керуючому файлі вказано значення %d"
+msgstr[3] "Розмір сегменту WAL повинен задаватись ступенем 2 в інтервалі від 1 МБ до 1 ГБ, але в керуючому файлі вказано значення %d"
+
+#: pg_rewind.c:1042 pg_rewind.c:1112
+#, c-format
+msgid "program \"%s\" is needed by %s but was not found in the same directory as \"%s\""
+msgstr "програма \"%s\" потрібна для %s, але не знайдена в тому ж каталозі, що й \"%s\""
+
+#: pg_rewind.c:1045 pg_rewind.c:1115
+#, c-format
+msgid "program \"%s\" was found by \"%s\" but was not the same version as %s"
+msgstr "програма \"%s\" знайдена для \"%s\", але має відмінну версію від %s"
+
+#: pg_rewind.c:1078
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "команда restore_command не встановлена в цільовому кластері"
+
+#: pg_rewind.c:1119
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "виконання \"%s\" для цільового серверу, щоб завершити відновлення після аварійного завершення роботи"
+
+#: pg_rewind.c:1156
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "не вдалося ввімкнути однокористувацький режим postgres в цільовому кластері"
+
+#: pg_rewind.c:1157
+#, c-format
+msgid "Command was: %s"
+msgstr "Команда була: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "синтаксична помилка у файлі історії: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "Очікується числовий ідентифікатор лінії часу."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Очікується положення точки випереджувального журналювання."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "неприпустимі дані у файлу історії: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "Ідентифікатори ліній часу повинні збільшуватись."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "неприпустимі дані у файлі історії"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "Ідентифікатори ліній часу повинні бути меншими від ідентифікатора дочірньої лінії."
+
+#: xlogreader.c:625
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "невірний зсув запису: %X/%X"
+
+#: xlogreader.c:633
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "по зсуву %X/%X запитано продовження запису"
+
+#: xlogreader.c:674 xlogreader.c:1121
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "невірна довжина запису по зсуву %X/%X: очікувалось %u, отримано %u"
+
+#: xlogreader.c:703
+#, c-format
+msgid "out of memory while trying to decode a record of length %u"
+msgstr "не вистачило пам'яті під час спроби закодування запису довжиною %u"
+
+#: xlogreader.c:725
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "довжина запису %u на %X/%X є задовгою"
+
+#: xlogreader.c:774
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "немає прапорця contrecord в позиції %X/%X"
+
+#: xlogreader.c:787
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "неприпустима довжина contrecord %u (очікувалось %lld) на %X/%X"
+
+#: xlogreader.c:922
+#, c-format
+msgid "missing contrecord at %X/%X"
+msgstr "відсутній contrecord в %X/%X"
+
+#: xlogreader.c:1129
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "невірний ID менеджера ресурсів %u в %X/%X"
+
+#: xlogreader.c:1142 xlogreader.c:1158
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "запис з неправильним попереднім посиланням %X/%X на %X/%X"
+
+#: xlogreader.c:1194
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "некоректна контрольна сума даних менеджера ресурсів у запису по зсуву %X/%X"
+
+#: xlogreader.c:1231
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "невірне магічне число %04X в сегменті журналу %s, зсув %u"
+
+#: xlogreader.c:1245 xlogreader.c:1286
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "невірні інформаційні біти %04X в сегменті журналу %s, зсув %u"
+
+#: xlogreader.c:1260
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "WAL файл належить іншій системі баз даних: ідентифікатор системи баз даних де міститься WAL файл - %llu, а ідентифікатор системи баз даних pg_control - %llu"
+
+#: xlogreader.c:1268
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "Файл WAL належить іншій системі баз даних: некоректний розмір сегменту в заголовку сторінки"
+
+#: xlogreader.c:1274
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "Файл WAL належить іншій системі баз даних: некоректний XLOG_BLCKSZ в заголовку сторінки"
+
+#: xlogreader.c:1305
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "неочікуваний pageaddr %X/%X в сегменті журналу %s, зсув %u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "порушення послідовності ID лінії часу %u (після %u) в сегменті журналу %s, зсув %u"
+
+#: xlogreader.c:1735
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "ідентифікатор блока %u out-of-order в позиції %X/%X"
+
+#: xlogreader.c:1759
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA встановлений, але немає даних в позиції %X/%X"
+
+#: xlogreader.c:1766
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA встановлений, але довжина даних дорівнює %u в позиції %X/%X"
+
+#: xlogreader.c:1802
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE встановлений, але для пропуску задані: зсув %u, довжина %u, при довжині образу блока %u в позиції %X/%X"
+
+#: xlogreader.c:1818
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE не встановлений, але для пропуску задані: зсув %u, довжина %u в позиції %X/%X"
+
+#: xlogreader.c:1832
+#, c-format
+msgid "BKPIMAGE_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_COMPRESSED встановлений, але довжина образу блока дорівнює %u в позиції %X/%X"
+
+#: xlogreader.c:1847
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "ні BKPIMAGE_HAS_HOLE, ні BKPIMAGE_COMPRESSED не встановлені, але довжина образу блока дорівнює %u в позиції %X/%X"
+
+#: xlogreader.c:1863
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "BKPBLOCK_SAME_REL встановлений, але попереднє значення не задано в позиції %X/%X"
+
+#: xlogreader.c:1875
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "невірний ідентифікатор блоку %u в позиції %X/%X"
+
+#: xlogreader.c:1942
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "запис з невірною довжиною на %X/%X"
+
+#: xlogreader.c:1967
+#, c-format
+msgid "could not locate backup block with ID %d in WAL record"
+msgstr "не вдалося знайти блок резервної копії з ID %d у записі WAL"
+
+#: xlogreader.c:2051
+#, c-format
+msgid "could not restore image at %X/%X with invalid block %d specified"
+msgstr "не вдалося відновити зображення %X/%X з недійсним вказаним блоком %d"
+
+#: xlogreader.c:2058
+#, c-format
+msgid "could not restore image at %X/%X with invalid state, block %d"
+msgstr "не вдалося відновити зображення %X/%X з недійсним станом, блок %d"
+
+#: xlogreader.c:2085 xlogreader.c:2102
+#, c-format
+msgid "could not restore image at %X/%X compressed with %s not supported by build, block %d"
+msgstr "не вдалося відновити зображення в %X/%X, стиснуте %s, не підтримується збіркою, блок %d"
+
+#: xlogreader.c:2111
+#, c-format
+msgid "could not restore image at %X/%X compressed with unknown method, block %d"
+msgstr "не вдалося відновити зображення %X/%X стиснуте з невідомим методом, блок %d"
+
+#: xlogreader.c:2119
+#, c-format
+msgid "could not decompress image at %X/%X, block %d"
+msgstr "не вдалося розпакувати зображення на %X/%X, блок %d"
+
diff --git a/src/bin/pg_rewind/po/zh_CN.po b/src/bin/pg_rewind/po/zh_CN.po
new file mode 100644
index 0000000..28d76c3
--- /dev/null
+++ b/src/bin/pg_rewind/po/zh_CN.po
@@ -0,0 +1,959 @@
+# LANGUAGE message translation file for pg_rewind
+# Copyright (C) 2019 PostgreSQL Global Development Group
+# This file is distributed under the same license as the PostgreSQL package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pg_rewind (PostgreSQL) 14\n"
+"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n"
+"POT-Creation-Date: 2021-08-14 05:48+0000\n"
+"PO-Revision-Date: 2021-08-15 10:00+0800\n"
+"Last-Translator: Jie Zhang <zhangjie2@fujitsu.com>\n"
+"Language-Team: Chinese (Simplified) <zhangjie2@fujitsu.com>\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 1.5.7\n"
+
+#: ../../../src/common/logging.c:259
+#, c-format
+msgid "fatal: "
+msgstr "致命的: "
+
+#: ../../../src/common/logging.c:266
+#, c-format
+msgid "error: "
+msgstr "错误: "
+
+#: ../../../src/common/logging.c:273
+#, c-format
+msgid "warning: "
+msgstr "警告: "
+
+#: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75
+#: ../../common/fe_memutils.c:98 ../../common/fe_memutils.c:162
+#, c-format
+msgid "out of memory\n"
+msgstr "内存不足\n"
+
+#: ../../common/fe_memutils.c:92 ../../common/fe_memutils.c:154
+#, c-format
+msgid "cannot duplicate null pointer (internal error)\n"
+msgstr "无法复制空指针 (内部错误)\n"
+
+#: ../../common/restricted_token.c:64
+#, c-format
+msgid "could not load library \"%s\": error code %lu"
+msgstr "无法加载库 \"%s\": 错误码 %lu"
+
+#: ../../common/restricted_token.c:73
+#, c-format
+msgid "cannot create restricted tokens on this platform: error code %lu"
+msgstr "无法为该平台创建受限制的令牌:错误码 %lu"
+
+#: ../../common/restricted_token.c:82
+#, c-format
+msgid "could not open process token: error code %lu"
+msgstr "无法打开进程令牌 (token): 错误码 %lu"
+
+#: ../../common/restricted_token.c:97
+#, c-format
+msgid "could not allocate SIDs: error code %lu"
+msgstr "无法分配SID: 错误码 %lu"
+
+#: ../../common/restricted_token.c:119
+#, c-format
+msgid "could not create restricted token: error code %lu"
+msgstr "无法创建受限令牌: 错误码为 %lu"
+
+#: ../../common/restricted_token.c:140
+#, c-format
+msgid "could not start process for command \"%s\": error code %lu"
+msgstr "无法为命令 \"%s\"创建进程: 错误码 %lu"
+
+#: ../../common/restricted_token.c:178
+#, c-format
+msgid "could not re-execute with restricted token: error code %lu"
+msgstr "无法使用受限令牌再次执行: 错误码 %lu"
+
+#: ../../common/restricted_token.c:194
+#, c-format
+msgid "could not get exit code from subprocess: error code %lu"
+msgstr "无法从子进程得到退出码: 错误码 %lu"
+
+#: ../../fe_utils/archive.c:53
+#, c-format
+msgid "cannot use restore_command with %%r placeholder"
+msgstr "无法对%%r占位符使用restore_command"
+
+#: ../../fe_utils/archive.c:74
+#, c-format
+msgid "unexpected file size for \"%s\": %lld instead of %lld"
+msgstr "\"%s\"的意外文件大小:%lld而不是%lld"
+
+#: ../../fe_utils/archive.c:85
+#, c-format
+msgid "could not open file \"%s\" restored from archive: %m"
+msgstr "无法打开从存档还原的文件\"%s\": %m"
+
+#: ../../fe_utils/archive.c:97 file_ops.c:417
+#, c-format
+msgid "could not stat file \"%s\": %m"
+msgstr "无法取文件 \"%s\" 的状态: %m"
+
+#: ../../fe_utils/archive.c:112
+#, c-format
+msgid "restore_command failed: %s"
+msgstr "restore_command失败: %s"
+
+#: ../../fe_utils/archive.c:121
+#, c-format
+msgid "could not restore file \"%s\" from archive"
+msgstr "无法从存档还原文件\"%s\""
+
+#: ../../fe_utils/recovery_gen.c:35 ../../fe_utils/recovery_gen.c:49
+#: ../../fe_utils/recovery_gen.c:77 ../../fe_utils/recovery_gen.c:100
+#: ../../fe_utils/recovery_gen.c:171 parsexlog.c:77 parsexlog.c:135
+#: parsexlog.c:195
+#, c-format
+msgid "out of memory"
+msgstr "内存不足"
+
+#: ../../fe_utils/recovery_gen.c:134 parsexlog.c:308
+#, c-format
+msgid "could not open file \"%s\": %m"
+msgstr "无法打开文件 \"%s\": %m"
+
+#: ../../fe_utils/recovery_gen.c:140
+#, c-format
+msgid "could not write to file \"%s\": %m"
+msgstr "无法写入文件 \"%s\": %m"
+
+#: ../../fe_utils/recovery_gen.c:152
+#, c-format
+msgid "could not create file \"%s\": %m"
+msgstr "无法创建文件 \"%s\": %m"
+
+#: file_ops.c:67
+#, c-format
+msgid "could not open target file \"%s\": %m"
+msgstr "无法打开目标文件\"%s\": %m"
+
+#: file_ops.c:81
+#, c-format
+msgid "could not close target file \"%s\": %m"
+msgstr "无法关闭目标文件\"%s\": %m"
+
+#: file_ops.c:101
+#, c-format
+msgid "could not seek in target file \"%s\": %m"
+msgstr "无法在目标文件\"%s\"中定位(seek): %m"
+
+#: file_ops.c:117
+#, c-format
+msgid "could not write file \"%s\": %m"
+msgstr "无法写入文件 \"%s\": %m"
+
+#: file_ops.c:150 file_ops.c:177
+#, c-format
+msgid "undefined file type for \"%s\""
+msgstr "不可识别的文件格式 \"%s\""
+
+#: file_ops.c:173
+#, c-format
+msgid "invalid action (CREATE) for regular file"
+msgstr "对常规文件无效的动作(CREATE)"
+
+#: file_ops.c:200
+#, c-format
+msgid "could not remove file \"%s\": %m"
+msgstr "无法删除文件 \"%s\": %m"
+
+#: file_ops.c:218
+#, c-format
+msgid "could not open file \"%s\" for truncation: %m"
+msgstr "无法打开文件\"%s\"用于截断:%m"
+
+#: file_ops.c:222
+#, c-format
+msgid "could not truncate file \"%s\" to %u: %m"
+msgstr "无法将文件\"%s\"截断为%u:%m"
+
+#: file_ops.c:238
+#, c-format
+msgid "could not create directory \"%s\": %m"
+msgstr "无法创建目录 \"%s\": %m"
+
+#: file_ops.c:252
+#, c-format
+msgid "could not remove directory \"%s\": %m"
+msgstr "无法删除目录 \"%s\": %m"
+
+#: file_ops.c:266
+#, c-format
+msgid "could not create symbolic link at \"%s\": %m"
+msgstr "无法在\"%s\"创建符号链接: %m"
+
+#: file_ops.c:280
+#, c-format
+msgid "could not remove symbolic link \"%s\": %m"
+msgstr "无法删除符号链接 \"%s\": %m"
+
+#: file_ops.c:326 file_ops.c:330
+#, c-format
+msgid "could not open file \"%s\" for reading: %m"
+msgstr "为了读取, 无法打开文件 \"%s\": %m"
+
+#: file_ops.c:341 local_source.c:107 parsexlog.c:346
+#, c-format
+msgid "could not read file \"%s\": %m"
+msgstr "无法读取文件 \"%s\": %m"
+
+#: file_ops.c:344 parsexlog.c:348
+#, c-format
+msgid "could not read file \"%s\": read %d of %zu"
+msgstr "无法读取文件\"%1$s\":读取了%3$zu中的%2$d"
+
+#: file_ops.c:388
+#, c-format
+msgid "could not open directory \"%s\": %m"
+msgstr "无法打开目录 \"%s\": %m"
+
+#: file_ops.c:446
+#, c-format
+msgid "could not read symbolic link \"%s\": %m"
+msgstr "无法读取符号链接 \"%s\": %m"
+
+#: file_ops.c:449
+#, c-format
+msgid "symbolic link \"%s\" target is too long"
+msgstr "符号链接 \"%s\" 目标超长"
+
+#: file_ops.c:464
+#, c-format
+msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform"
+msgstr "\"%s\"是一个符号链接,但是这个平台上不支持平台链接"
+
+#: file_ops.c:471
+#, c-format
+msgid "could not read directory \"%s\": %m"
+msgstr "无法读取目录 \"%s\": %m"
+
+#: file_ops.c:475
+#, c-format
+msgid "could not close directory \"%s\": %m"
+msgstr "无法关闭目录 \"%s\": %m"
+
+#: filemap.c:237
+#, c-format
+msgid "data file \"%s\" in source is not a regular file"
+msgstr "源头的数据文件\"%s\"不是一个常规文件"
+
+#: filemap.c:242 filemap.c:275
+#, c-format
+msgid "duplicate source file \"%s\""
+msgstr "复制源文件\"%s\""
+
+#: filemap.c:330
+#, c-format
+msgid "unexpected page modification for non-regular file \"%s\""
+msgstr "非常规文件\"%s\"的意外页面修改"
+
+#: filemap.c:680 filemap.c:774
+#, c-format
+msgid "unknown file type for \"%s\""
+msgstr "\"%s\"的未知文件类型"
+
+#: filemap.c:707
+#, c-format
+msgid "file \"%s\" is of different type in source and target"
+msgstr "文件 \"%s\"在源和目标中的类型不同"
+
+#: filemap.c:779
+#, c-format
+msgid "could not decide what to do with file \"%s\""
+msgstr "无法决定如何处理文件\"%s\""
+
+#: libpq_source.c:128
+#, c-format
+msgid "could not clear search_path: %s"
+msgstr "无法清除search_path: %s"
+
+#: libpq_source.c:139
+#, c-format
+msgid "full_page_writes must be enabled in the source server"
+msgstr "源服务器中的full_page_writes必须被启用"
+
+#: libpq_source.c:150
+#, c-format
+msgid "could not prepare statement to fetch file contents: %s"
+msgstr "无法准备语句以获取文件内容: %s"
+
+#: libpq_source.c:169
+#, c-format
+msgid "error running query (%s) on source server: %s"
+msgstr "源服务器中有错误运行的查询(%s):%s"
+
+#: libpq_source.c:174
+#, c-format
+msgid "unexpected result set from query"
+msgstr "从查询得到意料之外的结果集"
+
+#: libpq_source.c:196
+#, c-format
+msgid "error running query (%s) in source server: %s"
+msgstr "源服务器中有错误运行的查询(%s):%s"
+
+#: libpq_source.c:217
+#, c-format
+msgid "unrecognized result \"%s\" for current WAL insert location"
+msgstr "当前WAL插入位置的未识别结果\"%s\""
+
+#: libpq_source.c:268
+#, c-format
+msgid "could not fetch file list: %s"
+msgstr "无法取得文件列表:%s"
+
+#: libpq_source.c:273
+#, c-format
+msgid "unexpected result set while fetching file list"
+msgstr "在取得文件列表时得到意料之外的结果集"
+
+#: libpq_source.c:435
+#, c-format
+msgid "could not send query: %s"
+msgstr "无法发送查询:%s"
+
+#: libpq_source.c:438
+#, c-format
+msgid "could not set libpq connection to single row mode"
+msgstr "无法设置libpq连接为单行模式"
+
+#: libpq_source.c:468
+#, c-format
+msgid "unexpected result while fetching remote files: %s"
+msgstr "在取得远程文件时得到意料之外的结果:%s"
+
+#: libpq_source.c:473
+#, c-format
+msgid "received more data chunks than requested"
+msgstr "收到的数据块比请求的多"
+
+#: libpq_source.c:477
+#, c-format
+msgid "unexpected result set size while fetching remote files"
+msgstr "在取得远程文件时得到意料之外的结果集大小"
+
+#: libpq_source.c:483
+#, c-format
+msgid "unexpected data types in result set while fetching remote files: %u %u %u"
+msgstr "在取得远程文件时结果集中有意料之外的数据类型:%u %u %u"
+
+#: libpq_source.c:491
+#, c-format
+msgid "unexpected result format while fetching remote files"
+msgstr "在取得远程文件时得到意料之外的结果格式"
+
+#: libpq_source.c:497
+#, c-format
+msgid "unexpected null values in result while fetching remote files"
+msgstr "在取得远程文件时结果中有意料之外的空值"
+
+#: libpq_source.c:501
+#, c-format
+msgid "unexpected result length while fetching remote files"
+msgstr "在取得远程文件时得到意料之外的结果长度"
+
+#: libpq_source.c:534
+#, c-format
+msgid "received data for file \"%s\", when requested for \"%s\""
+msgstr "当为文件\"%2$s\"请求时,接收到文件\"%1$s\"的数据"
+
+#: libpq_source.c:538
+#, c-format
+msgid "received data at offset %lld of file \"%s\", when requested for offset %lld"
+msgstr "当请求偏移量%3$lld时,在文件\"%2$s\"的偏移量%1$lld处接收到数据"
+
+#: libpq_source.c:550
+#, c-format
+msgid "received more than requested for file \"%s\""
+msgstr "收到的文件\"%s\"比要求的多"
+
+#: libpq_source.c:563
+#, c-format
+msgid "unexpected number of data chunks received"
+msgstr "接收到意外的数据块数"
+
+#: libpq_source.c:606
+#, c-format
+msgid "could not fetch remote file \"%s\": %s"
+msgstr "无法取得远程文件\"%s\": %s"
+
+#: libpq_source.c:611
+#, c-format
+msgid "unexpected result set while fetching remote file \"%s\""
+msgstr "在取得远程文件\"%s\"时得到意料之外的结果集"
+
+#: local_source.c:86
+#, c-format
+msgid "could not open source file \"%s\": %m"
+msgstr "无法打开源文件\"%s\": %m"
+
+#: local_source.c:90
+#, c-format
+msgid "could not seek in source file: %m"
+msgstr "无法在源文件中定位(seek):%m"
+
+#: local_source.c:109
+#, c-format
+msgid "unexpected EOF while reading file \"%s\""
+msgstr "读取文件\"%s\"时遇到意料之外的EOF"
+
+#: local_source.c:116
+#, c-format
+msgid "could not close file \"%s\": %m"
+msgstr "无法关闭文件 \"%s\": %m"
+
+#: parsexlog.c:89 parsexlog.c:142
+#, c-format
+msgid "could not read WAL record at %X/%X: %s"
+msgstr "无法读取%X/%X处的WAL记录:%s"
+
+#: parsexlog.c:93 parsexlog.c:145
+#, c-format
+msgid "could not read WAL record at %X/%X"
+msgstr "无法读取%X/%X处的WAL记录"
+
+#: parsexlog.c:208
+#, c-format
+msgid "could not find previous WAL record at %X/%X: %s"
+msgstr "无法在%X/%X找到前一个WAL记录:%s"
+
+#: parsexlog.c:212
+#, c-format
+msgid "could not find previous WAL record at %X/%X"
+msgstr "无法在%X/%X找到前一个WAL记录"
+
+#: parsexlog.c:337
+#, c-format
+msgid "could not seek in file \"%s\": %m"
+msgstr "无法在文件\"%s\"进行查找: %m"
+
+#: parsexlog.c:429
+#, c-format
+msgid "WAL record modifies a relation, but record type is not recognized: lsn: %X/%X, rmgr: %s, info: %02X"
+msgstr "WAL记录修改了一个关系,但是记录类型无法识别: lsn: %X/%X, rmgr: %s, info: %02X"
+
+#: pg_rewind.c:84
+#, c-format
+msgid ""
+"%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n"
+"\n"
+msgstr ""
+"%s用一个PostgreSQL集簇的另一个拷贝重新同步了该集簇。\n"
+"\n"
+
+#: pg_rewind.c:85
+#, c-format
+msgid ""
+"Usage:\n"
+" %s [OPTION]...\n"
+"\n"
+msgstr ""
+"用法:\n"
+" %s [选项]...\n"
+"\n"
+
+#: pg_rewind.c:86
+#, c-format
+msgid "Options:\n"
+msgstr "选项:\n"
+
+#: pg_rewind.c:87
+#, c-format
+msgid ""
+" -c, --restore-target-wal use restore_command in target configuration to\n"
+" retrieve WAL files from archives\n"
+msgstr ""
+" -c, --restore-target-wal 在目标配置中使用restore_command\n"
+" 从存档中检索WAL文件\n"
+
+#: pg_rewind.c:89
+#, c-format
+msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n"
+msgstr " -D, --target-pgdata=DIRECTORY 已有的要修改的数据目录\n"
+
+#: pg_rewind.c:90
+#, c-format
+msgid " --source-pgdata=DIRECTORY source data directory to synchronize with\n"
+msgstr " --source-pgdata=DIRECTORY 要与之同步的源数据目录\n"
+
+#: pg_rewind.c:91
+#, c-format
+msgid " --source-server=CONNSTR source server to synchronize with\n"
+msgstr " --source-server=CONNSTR 要与之同步的源服务器\n"
+
+#: pg_rewind.c:92
+#, c-format
+msgid " -n, --dry-run stop before modifying anything\n"
+msgstr " -n, --dry-run 在修改任何东西之前停止\n"
+
+#: pg_rewind.c:93
+#, c-format
+msgid ""
+" -N, --no-sync do not wait for changes to be written\n"
+" safely to disk\n"
+msgstr ""
+" -N, --no-sync 不用等待变化安全\n"
+" 写入磁盘\n"
+
+#: pg_rewind.c:95
+#, c-format
+msgid " -P, --progress write progress messages\n"
+msgstr " -P, --progress 写出进度消息\n"
+
+#: pg_rewind.c:96
+#, c-format
+msgid ""
+" -R, --write-recovery-conf write configuration for replication\n"
+" (requires --source-server)\n"
+msgstr ""
+" -R, --write-recovery-conf 为复制写配置文\n"
+" (requires --source-server)\n"
+
+#: pg_rewind.c:98
+#, c-format
+msgid " --debug write a lot of debug messages\n"
+msgstr " --debug 写出很多调试消息\n"
+
+#: pg_rewind.c:99
+#, c-format
+msgid " --no-ensure-shutdown do not automatically fix unclean shutdown\n"
+msgstr " --no-ensure-shutdown 不要自动修复不干净的关机\n"
+
+#: pg_rewind.c:100
+#, c-format
+msgid " -V, --version output version information, then exit\n"
+msgstr " -V, --version 输出版本信息,然后退出\n"
+
+#: pg_rewind.c:101
+#, c-format
+msgid " -?, --help show this help, then exit\n"
+msgstr " -?, --help 显示本帮助,然后退出\n"
+
+#: pg_rewind.c:102
+#, c-format
+msgid ""
+"\n"
+"Report bugs to <%s>.\n"
+msgstr ""
+"\n"
+"臭虫报告至<%s>.\n"
+
+#: pg_rewind.c:103
+#, c-format
+msgid "%s home page: <%s>\n"
+msgstr "%s 主页: <%s>\n"
+
+#: pg_rewind.c:164 pg_rewind.c:213 pg_rewind.c:220 pg_rewind.c:227
+#: pg_rewind.c:234 pg_rewind.c:242
+#, c-format
+msgid "Try \"%s --help\" for more information.\n"
+msgstr "请用 \"%s --help\" 获取更多的信息.\n"
+
+#: pg_rewind.c:212
+#, c-format
+msgid "no source specified (--source-pgdata or --source-server)"
+msgstr "没有指定源 (--source-pgdata 或者 --source-server)"
+
+#: pg_rewind.c:219
+#, c-format
+msgid "only one of --source-pgdata or --source-server can be specified"
+msgstr "只能指定--source-pgdata和--source-server这两个选项之一"
+
+#: pg_rewind.c:226
+#, c-format
+msgid "no target data directory specified (--target-pgdata)"
+msgstr "没有指定目标数据目录 (--target-pgdata)"
+
+#: pg_rewind.c:233
+#, c-format
+msgid "no source server information (--source-server) specified for --write-recovery-conf"
+msgstr "没有为--write-recovery-conf指定源服务器信息(--source-server)"
+
+#: pg_rewind.c:240
+#, c-format
+msgid "too many command-line arguments (first is \"%s\")"
+msgstr "命令行参数太多 (第一个是 \"%s\")"
+
+#: pg_rewind.c:255
+#, c-format
+msgid "cannot be executed by \"root\""
+msgstr "不能由\"root\"执行"
+
+#: pg_rewind.c:256
+#, c-format
+msgid "You must run %s as the PostgreSQL superuser.\n"
+msgstr "您现在作为PostgreSQL超级用户运行%s.\n"
+
+#: pg_rewind.c:267
+#, c-format
+msgid "could not read permissions of directory \"%s\": %m"
+msgstr "没有读取目录 \"%s\" 的权限: %m"
+
+#: pg_rewind.c:287
+#, c-format
+msgid "%s"
+msgstr "%s"
+
+#: pg_rewind.c:290
+#, c-format
+msgid "connected to server"
+msgstr "已连接服务器"
+
+#: pg_rewind.c:337
+#, c-format
+msgid "source and target cluster are on the same timeline"
+msgstr "源集簇和目标集簇处于同一时间线"
+
+#: pg_rewind.c:346
+#, c-format
+msgid "servers diverged at WAL location %X/%X on timeline %u"
+msgstr "服务器在时间线%3$u上的WAL位置%1$X/%2$X处发生了分歧"
+
+#: pg_rewind.c:394
+#, c-format
+msgid "no rewind required"
+msgstr "不需要倒带(rewind)"
+
+#: pg_rewind.c:403
+#, c-format
+msgid "rewinding from last common checkpoint at %X/%X on timeline %u"
+msgstr "从时间线%3$u上%1$X/%2$X处的最后一个普通检查点倒带"
+
+#: pg_rewind.c:413
+#, c-format
+msgid "reading source file list"
+msgstr "读取源文件列表"
+
+#: pg_rewind.c:417
+#, c-format
+msgid "reading target file list"
+msgstr "读取目标文件列表"
+
+#: pg_rewind.c:426
+#, c-format
+msgid "reading WAL in target"
+msgstr "读取目标中的WAL"
+
+#: pg_rewind.c:447
+#, c-format
+msgid "need to copy %lu MB (total source directory size is %lu MB)"
+msgstr "需要复制 %lu MB(整个源目录的大小是 %lu MB)"
+
+#: pg_rewind.c:465
+#, c-format
+msgid "syncing target data directory"
+msgstr "正在同步目标数据目录"
+
+#: pg_rewind.c:481
+#, c-format
+msgid "Done!"
+msgstr "完成!"
+
+#: pg_rewind.c:564
+#, c-format
+msgid "no action decided for file \"%s\""
+msgstr "未决定对文件\"%s\"执行任何操作"
+
+#: pg_rewind.c:596
+#, c-format
+msgid "source system was modified while pg_rewind was running"
+msgstr "pg_rewind运行时修改了源系统"
+
+#: pg_rewind.c:600
+#, c-format
+msgid "creating backup label and updating control file"
+msgstr "正在创建备份标签并且更新控制文件"
+
+#: pg_rewind.c:650
+#, c-format
+msgid "source system was in unexpected state at end of rewind"
+msgstr "源系统在rewind结束时处于意外状态"
+
+#: pg_rewind.c:681
+#, c-format
+msgid "source and target clusters are from different systems"
+msgstr "源集簇和目标集簇来自不同的系统"
+
+#: pg_rewind.c:689
+#, c-format
+msgid "clusters are not compatible with this version of pg_rewind"
+msgstr "集簇与这个pg_rewind的版本不兼容"
+
+#: pg_rewind.c:699
+#, c-format
+msgid "target server needs to use either data checksums or \"wal_log_hints = on\""
+msgstr "目标服务器需要使用数据校验和或者让\"wal_log_hints = on\""
+
+#: pg_rewind.c:710
+#, c-format
+msgid "target server must be shut down cleanly"
+msgstr "目标服务器必须被干净地关闭"
+
+#: pg_rewind.c:720
+#, c-format
+msgid "source data directory must be shut down cleanly"
+msgstr "源数据目录必须被干净地关闭"
+
+#: pg_rewind.c:772
+#, c-format
+msgid "%*s/%s kB (%d%%) copied"
+msgstr "已复制%*s/%s kB (%d%%)"
+
+#: pg_rewind.c:835
+#, c-format
+msgid "invalid control file"
+msgstr "无效的控制文件"
+
+#: pg_rewind.c:919
+#, c-format
+msgid "could not find common ancestor of the source and target cluster's timelines"
+msgstr "无法找到源集簇和目标集簇的时间线的共同祖先"
+
+#: pg_rewind.c:960
+#, c-format
+msgid "backup label buffer too small"
+msgstr "备份标签缓冲太小"
+
+#: pg_rewind.c:983
+#, c-format
+msgid "unexpected control file CRC"
+msgstr "意料之外的控制文件CRC"
+
+#: pg_rewind.c:995
+#, c-format
+msgid "unexpected control file size %d, expected %d"
+msgstr "意料之外的控制文件大小%d,应该是%d"
+
+#: pg_rewind.c:1004
+#, c-format
+msgid "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d byte"
+msgid_plural "WAL segment size must be a power of two between 1 MB and 1 GB, but the control file specifies %d bytes"
+msgstr[0] "WAL段大小必须是1 MB到1 GB之间的2的幂,但控制文件指定了%d字节"
+msgstr[1] "WAL段大小必须是1 MB到1 GB之间的2的幂,但控制文件指定了%d字节"
+
+#: pg_rewind.c:1043 pg_rewind.c:1101
+#, c-format
+msgid ""
+"The program \"%s\" is needed by %s but was not found in the\n"
+"same directory as \"%s\".\n"
+"Check your installation."
+msgstr ""
+"%2$s需要程序\"%1$s\"\n"
+"但在与\"%3$s\"相同的目录中找不到该程序.\n"
+"检查您的安装."
+
+#: pg_rewind.c:1048 pg_rewind.c:1106
+#, c-format
+msgid ""
+"The program \"%s\" was found by \"%s\"\n"
+"but was not the same version as %s.\n"
+"Check your installation."
+msgstr ""
+"程序\"%s\"是由\"%s\"找到的\n"
+"但与%s的版本不同.\n"
+"检查您的安装."
+
+#: pg_rewind.c:1069
+#, c-format
+msgid "restore_command is not set in the target cluster"
+msgstr "目标群集中未设置restore_command"
+
+#: pg_rewind.c:1112
+#, c-format
+msgid "executing \"%s\" for target server to complete crash recovery"
+msgstr "对目标服务器执行\"%s\"以完成崩溃恢复"
+
+#: pg_rewind.c:1132
+#, c-format
+msgid "postgres single-user mode in target cluster failed"
+msgstr "目标群集中的postgres单用户模式失败"
+
+#: pg_rewind.c:1133
+#, c-format
+msgid "Command was: %s"
+msgstr "命令是: %s"
+
+#: timeline.c:75 timeline.c:81
+#, c-format
+msgid "syntax error in history file: %s"
+msgstr "历史文件中的语法错误: %s"
+
+#: timeline.c:76
+#, c-format
+msgid "Expected a numeric timeline ID."
+msgstr "期望一个数字 timeline ID."
+
+#: timeline.c:82
+#, c-format
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "期望一个预写日志切换点位置."
+
+#: timeline.c:87
+#, c-format
+msgid "invalid data in history file: %s"
+msgstr "历史文件中的无效数据: %s"
+
+#: timeline.c:88
+#, c-format
+msgid "Timeline IDs must be in increasing sequence."
+msgstr "TimeLine ID 必须为递增序列."
+
+#: timeline.c:108
+#, c-format
+msgid "invalid data in history file"
+msgstr "历史文件中有无效数据"
+
+#: timeline.c:109
+#, c-format
+msgid "Timeline IDs must be less than child timeline's ID."
+msgstr "Timeline ID 必须小于子 timeline 的 ID."
+
+#: xlogreader.c:349
+#, c-format
+msgid "invalid record offset at %X/%X"
+msgstr "%X/%X处有无效的记录偏移量"
+
+#: xlogreader.c:357
+#, c-format
+msgid "contrecord is requested by %X/%X"
+msgstr "%X/%X位置处要求继续记录"
+
+#: xlogreader.c:398 xlogreader.c:695
+#, c-format
+msgid "invalid record length at %X/%X: wanted %u, got %u"
+msgstr "%X/%X处有无效记录长度: 应该是%u, 但实际是%u"
+
+#: xlogreader.c:422
+#, c-format
+msgid "record length %u at %X/%X too long"
+msgstr "%2$X/%3$X处的记录长度%1$u太长"
+
+#: xlogreader.c:453
+#, c-format
+msgid "there is no contrecord flag at %X/%X"
+msgstr "在%X/%X处没有继续记录标志"
+
+#: xlogreader.c:466
+#, c-format
+msgid "invalid contrecord length %u (expected %lld) at %X/%X"
+msgstr "%3$X/%4$X处有无效的继续记录长度%1$u(应为 %2$lld)"
+
+#: xlogreader.c:703
+#, c-format
+msgid "invalid resource manager ID %u at %X/%X"
+msgstr "%2$X/%3$X处有无效的资源管理器 ID %1$u"
+
+#: xlogreader.c:716 xlogreader.c:732
+#, c-format
+msgid "record with incorrect prev-link %X/%X at %X/%X"
+msgstr "具有不正确向前链接%X/%X的记录出现在%X/%X"
+
+#: xlogreader.c:768
+#, c-format
+msgid "incorrect resource manager data checksum in record at %X/%X"
+msgstr "在%X/%X处的记录中的资源管理器数据校验和不正确"
+
+#: xlogreader.c:805
+#, c-format
+msgid "invalid magic number %04X in log segment %s, offset %u"
+msgstr "在日志段%2$s的偏移量%3$u处有无效的magic号%1$04X"
+
+#: xlogreader.c:819 xlogreader.c:860
+#, c-format
+msgid "invalid info bits %04X in log segment %s, offset %u"
+msgstr "在日志段%2$s的偏移量%3$u处有无效的info位%1$04X"
+
+#: xlogreader.c:834
+#, c-format
+msgid "WAL file is from different database system: WAL file database system identifier is %llu, pg_control database system identifier is %llu"
+msgstr "WAL文件来自于不同的数据库系统:WAL文件数据库系统标识符是%llu,pg_control数据库系统标识符是%llu"
+
+#: xlogreader.c:842
+#, c-format
+msgid "WAL file is from different database system: incorrect segment size in page header"
+msgstr "WAL文件来自于不同的数据库系统:页头部中有不正确的段大小"
+
+#: xlogreader.c:848
+#, c-format
+msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
+msgstr "WAL文件来自于不同的数据库系统:页头部中有不正确的XLOG_BLCKSZ"
+
+#: xlogreader.c:879
+#, c-format
+msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
+msgstr "在日志段%3$s的偏移量%4$u处有意料之外的pageaddr %1$X/%2$X"
+
+#: xlogreader.c:904
+#, c-format
+msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
+msgstr "在日志段%3$s的偏移量%4$u处有失序的时间线 ID %1$u(在%2$u之后)"
+
+#: xlogreader.c:1249
+#, c-format
+msgid "out-of-order block_id %u at %X/%X"
+msgstr "在%2$X/%3$X处有无序的block_id %1$u"
+
+#: xlogreader.c:1271
+#, c-format
+msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA已被设置,但是在%X/%X处没有包括数据"
+
+#: xlogreader.c:1278
+#, c-format
+msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
+msgstr "BKPBLOCK_HAS_DATA没有被设置,但是在%2$X/%3$X处的数据长度为%1$u"
+
+#: xlogreader.c:1314
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE已被设置,但是%4$X/%5$X处记录了洞偏移量为%1$u、长度为%2$u、块映像长度为%3$u"
+
+#: xlogreader.c:1330
+#, c-format
+msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE没有被设置,但是%3$X/%4$X处记录了洞偏移量为%1$u、长度为%2$u"
+
+#: xlogreader.c:1345
+#, c-format
+msgid "BKPIMAGE_IS_COMPRESSED set, but block image length %u at %X/%X"
+msgstr "BKPIMAGE_IS_COMPRESSED已被设置,但是%2$X/%3$X处记录的块映像长度为%1$u"
+
+#: xlogreader.c:1360
+#, c-format
+msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_IS_COMPRESSED set, but block image length is %u at %X/%X"
+msgstr "BKPIMAGE_HAS_HOLE和BKPIMAGE_IS_COMPRESSED都没有被设置,但是%2$X/%3$X处记录的块映像长度为%1$u"
+
+#: xlogreader.c:1376
+#, c-format
+msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
+msgstr "设置了BKPBLOCK_SAME_REL,但是在%X/%X位置没有记录先前的关系"
+
+#: xlogreader.c:1388
+#, c-format
+msgid "invalid block_id %u at %X/%X"
+msgstr "%2$X/%3$X处的block_id %1$u无效"
+
+#: xlogreader.c:1475
+#, c-format
+msgid "record with invalid length at %X/%X"
+msgstr "在%X/%X处的记录的长度无效"
+
+#: xlogreader.c:1564
+#, c-format
+msgid "invalid compressed image at %X/%X, block %d"
+msgstr "%X/%X处是块%d的无效压缩映像"
diff --git a/src/bin/pg_rewind/rewind_source.h b/src/bin/pg_rewind/rewind_source.h
new file mode 100644
index 0000000..1310e86
--- /dev/null
+++ b/src/bin/pg_rewind/rewind_source.h
@@ -0,0 +1,86 @@
+/*-------------------------------------------------------------------------
+ *
+ * rewind_source.h
+ * Abstraction for fetching from source server.
+ *
+ * The source server can be either a libpq connection to a live system,
+ * or a local data directory. The 'rewind_source' struct abstracts the
+ * operations to fetch data from the source system, so that the rest of
+ * the code doesn't need to care what kind of a source its dealing with.
+ *
+ * Copyright (c) 2013-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef REWIND_SOURCE_H
+#define REWIND_SOURCE_H
+
+#include "access/xlogdefs.h"
+#include "file_ops.h"
+#include "filemap.h"
+#include "libpq-fe.h"
+
+typedef struct rewind_source
+{
+ /*
+ * Traverse all files in the source data directory, and call 'callback' on
+ * each file.
+ */
+ void (*traverse_files) (struct rewind_source *,
+ process_file_callback_t callback);
+
+ /*
+ * Fetch a single file into a malloc'd buffer. The file size is returned
+ * in *filesize. The returned buffer is always zero-terminated, which is
+ * handy for text files.
+ */
+ char *(*fetch_file) (struct rewind_source *, const char *path,
+ size_t *filesize);
+
+ /*
+ * Request to fetch (part of) a file in the source system, specified by an
+ * offset and length, and write it to the same offset in the corresponding
+ * target file. The source implementation may queue up the request and
+ * execute it later when convenient. Call finish_fetch() to flush the
+ * queue and execute all requests.
+ */
+ void (*queue_fetch_range) (struct rewind_source *, const char *path,
+ off_t offset, size_t len);
+
+ /*
+ * Like queue_fetch_range(), but requests replacing the whole local file
+ * from the source system. 'len' is the expected length of the file,
+ * although when the source is a live server, the file may change
+ * concurrently. The implementation is not obliged to copy more than 'len'
+ * bytes, even if the file is larger. However, to avoid copying a
+ * truncated version of the file, which can cause trouble if e.g. a
+ * configuration file is modified concurrently, the implementation should
+ * try to copy the whole file, even if it's larger than expected.
+ */
+ void (*queue_fetch_file) (struct rewind_source *, const char *path,
+ size_t len);
+
+ /*
+ * Execute all requests queued up with queue_fetch_range().
+ */
+ void (*finish_fetch) (struct rewind_source *);
+
+ /*
+ * Get the current WAL insert position in the source system.
+ */
+ XLogRecPtr (*get_current_wal_insert_lsn) (struct rewind_source *);
+
+ /*
+ * Free this rewind_source object.
+ */
+ void (*destroy) (struct rewind_source *);
+
+} rewind_source;
+
+/* in libpq_source.c */
+extern rewind_source *init_libpq_source(PGconn *conn);
+
+/* in local_source.c */
+extern rewind_source *init_local_source(const char *datadir);
+
+#endif /* FETCH_H */
diff --git a/src/bin/pg_rewind/t/001_basic.pl b/src/bin/pg_rewind/t/001_basic.pl
new file mode 100644
index 0000000..db9201f
--- /dev/null
+++ b/src/bin/pg_rewind/t/001_basic.pl
@@ -0,0 +1,194 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use RewindTest;
+
+sub run_test
+{
+ my $test_mode = shift;
+
+ RewindTest::setup_cluster($test_mode);
+ RewindTest::start_primary();
+
+ # Create a test table and insert a row in primary.
+ primary_psql("CREATE TABLE tbl1 (d text)");
+ primary_psql("INSERT INTO tbl1 VALUES ('in primary')");
+
+ # This test table will be used to test truncation, i.e. the table
+ # is extended in the old primary after promotion
+ primary_psql("CREATE TABLE trunc_tbl (d text)");
+ primary_psql("INSERT INTO trunc_tbl VALUES ('in primary')");
+
+ # This test table will be used to test the "copy-tail" case, i.e. the
+ # table is truncated in the old primary after promotion
+ primary_psql("CREATE TABLE tail_tbl (id integer, d text)");
+ primary_psql("INSERT INTO tail_tbl VALUES (0, 'in primary')");
+
+ # This test table is dropped in the old primary after promotion.
+ primary_psql("CREATE TABLE drop_tbl (d text)");
+ primary_psql("INSERT INTO drop_tbl VALUES ('in primary')");
+
+ primary_psql("CHECKPOINT");
+
+ RewindTest::create_standby($test_mode);
+
+ # Insert additional data on primary that will be replicated to standby
+ primary_psql("INSERT INTO tbl1 values ('in primary, before promotion')");
+ primary_psql(
+ "INSERT INTO trunc_tbl values ('in primary, before promotion')");
+ primary_psql(
+ "INSERT INTO tail_tbl SELECT g, 'in primary, before promotion: ' || g FROM generate_series(1, 10000) g"
+ );
+
+ primary_psql('CHECKPOINT');
+
+ RewindTest::promote_standby();
+
+ # Insert a row in the old primary. This causes the primary and standby
+ # to have "diverged", it's no longer possible to just apply the
+ # standy's logs over primary directory - you need to rewind.
+ primary_psql("INSERT INTO tbl1 VALUES ('in primary, after promotion')");
+
+ # Also insert a new row in the standby, which won't be present in the
+ # old primary.
+ standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");
+
+ # Insert enough rows to trunc_tbl to extend the file. pg_rewind should
+ # truncate it back to the old size.
+ primary_psql(
+ "INSERT INTO trunc_tbl SELECT 'in primary, after promotion: ' || g FROM generate_series(1, 10000) g"
+ );
+
+ # Truncate tail_tbl. pg_rewind should copy back the truncated part
+ # (We cannot use an actual TRUNCATE command here, as that creates a
+ # whole new relfilenode)
+ primary_psql("DELETE FROM tail_tbl WHERE id > 10");
+ primary_psql("VACUUM tail_tbl");
+
+ # Drop drop_tbl. pg_rewind should copy it back.
+ primary_psql(
+ "insert into drop_tbl values ('in primary, after promotion')");
+ primary_psql("DROP TABLE drop_tbl");
+
+ # Before running pg_rewind, do a couple of extra tests with several
+ # option combinations. As the code paths taken by those tests
+ # do not change for the "local" and "remote" modes, just run them
+ # in "local" mode for simplicity's sake.
+ if ($test_mode eq 'local')
+ {
+ my $primary_pgdata = $node_primary->data_dir;
+ my $standby_pgdata = $node_standby->data_dir;
+
+ # First check that pg_rewind fails if the target cluster is
+ # not stopped as it fails to start up for the forced recovery
+ # step.
+ command_fails(
+ [
+ 'pg_rewind', '--debug',
+ '--source-pgdata', $standby_pgdata,
+ '--target-pgdata', $primary_pgdata,
+ '--no-sync'
+ ],
+ 'pg_rewind with running target');
+
+ # Again with --no-ensure-shutdown, which should equally fail.
+ # This time pg_rewind complains without attempting to perform
+ # recovery once.
+ command_fails(
+ [
+ 'pg_rewind', '--debug',
+ '--source-pgdata', $standby_pgdata,
+ '--target-pgdata', $primary_pgdata,
+ '--no-sync', '--no-ensure-shutdown'
+ ],
+ 'pg_rewind --no-ensure-shutdown with running target');
+
+ # Stop the target, and attempt to run with a local source
+ # still running. This fails as pg_rewind requires to have
+ # a source cleanly stopped.
+ $node_primary->stop;
+ command_fails(
+ [
+ 'pg_rewind', '--debug',
+ '--source-pgdata', $standby_pgdata,
+ '--target-pgdata', $primary_pgdata,
+ '--no-sync', '--no-ensure-shutdown'
+ ],
+ 'pg_rewind with unexpected running source');
+
+ # Stop the target cluster cleanly, and run again pg_rewind
+ # with --dry-run mode. If anything gets generated in the data
+ # folder, the follow-up run of pg_rewind will most likely fail,
+ # so keep this test as the last one of this subset.
+ $node_standby->stop;
+ command_ok(
+ [
+ 'pg_rewind', '--debug',
+ '--source-pgdata', $standby_pgdata,
+ '--target-pgdata', $primary_pgdata,
+ '--no-sync', '--dry-run'
+ ],
+ 'pg_rewind --dry-run');
+
+ # Both clusters need to be alive moving forward.
+ $node_standby->start;
+ $node_primary->start;
+ }
+
+ RewindTest::run_pg_rewind($test_mode);
+
+ check_query(
+ 'SELECT * FROM tbl1',
+ qq(in primary
+in primary, before promotion
+in standby, after promotion
+),
+ 'table content');
+
+ check_query(
+ 'SELECT * FROM trunc_tbl',
+ qq(in primary
+in primary, before promotion
+),
+ 'truncation');
+
+ check_query(
+ 'SELECT count(*) FROM tail_tbl',
+ qq(10001
+),
+ 'tail-copy');
+
+ check_query(
+ 'SELECT * FROM drop_tbl',
+ qq(in primary
+),
+ 'drop');
+
+ # Permissions on PGDATA should be default
+ SKIP:
+ {
+ skip "unix-style permissions not supported on Windows", 1
+ if ($windows_os);
+
+ ok(check_mode_recursive($node_primary->data_dir(), 0700, 0600),
+ 'check PGDATA permissions');
+ }
+
+ RewindTest::clean_rewind_test();
+ return;
+}
+
+# Run the test in both modes
+run_test('local');
+run_test('remote');
+run_test('archive');
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/002_databases.pl b/src/bin/pg_rewind/t/002_databases.pl
new file mode 100644
index 0000000..8d6c0c0
--- /dev/null
+++ b/src/bin/pg_rewind/t/002_databases.pl
@@ -0,0 +1,77 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use RewindTest;
+
+sub run_test
+{
+ my $test_mode = shift;
+
+ RewindTest::setup_cluster($test_mode, ['-g']);
+ RewindTest::start_primary();
+
+ # Create a database in primary with a table.
+ primary_psql('CREATE DATABASE inprimary');
+ primary_psql('CREATE TABLE inprimary_tab (a int)', 'inprimary');
+
+ RewindTest::create_standby($test_mode);
+
+ # Create another database with another table, the creation is
+ # replicated to the standby.
+ primary_psql('CREATE DATABASE beforepromotion');
+ primary_psql('CREATE TABLE beforepromotion_tab (a int)',
+ 'beforepromotion');
+
+ RewindTest::promote_standby();
+
+ # Create databases in the old primary and the new promoted standby.
+ primary_psql('CREATE DATABASE primary_afterpromotion');
+ primary_psql('CREATE TABLE primary_promotion_tab (a int)',
+ 'primary_afterpromotion');
+ standby_psql('CREATE DATABASE standby_afterpromotion');
+ standby_psql('CREATE TABLE standby_promotion_tab (a int)',
+ 'standby_afterpromotion');
+
+ # The clusters are now diverged.
+
+ RewindTest::run_pg_rewind($test_mode);
+
+ # Check that the correct databases are present after pg_rewind.
+ check_query(
+ 'SELECT datname FROM pg_database ORDER BY 1',
+ qq(beforepromotion
+inprimary
+postgres
+standby_afterpromotion
+template0
+template1
+),
+ 'database names');
+
+ # Permissions on PGDATA should have group permissions
+ SKIP:
+ {
+ skip "unix-style permissions not supported on Windows", 1
+ if ($windows_os);
+
+ ok(check_mode_recursive($node_primary->data_dir(), 0750, 0640),
+ 'check PGDATA permissions');
+ }
+
+ RewindTest::clean_rewind_test();
+ return;
+}
+
+# Run the test in both modes.
+run_test('local');
+run_test('remote');
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/003_extrafiles.pl b/src/bin/pg_rewind/t/003_extrafiles.pl
new file mode 100644
index 0000000..b1c47ea
--- /dev/null
+++ b/src/bin/pg_rewind/t/003_extrafiles.pl
@@ -0,0 +1,106 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+# Test how pg_rewind reacts to extra files and directories in the data dirs.
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use File::Find;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use RewindTest;
+
+
+sub run_test
+{
+ my $test_mode = shift;
+
+ RewindTest::setup_cluster($test_mode);
+ RewindTest::start_primary();
+
+ my $test_primary_datadir = $node_primary->data_dir;
+
+ # Create a subdir and files that will be present in both
+ mkdir "$test_primary_datadir/tst_both_dir";
+ append_to_file "$test_primary_datadir/tst_both_dir/both_file1",
+ "in both1";
+ append_to_file "$test_primary_datadir/tst_both_dir/both_file2",
+ "in both2";
+ mkdir "$test_primary_datadir/tst_both_dir/both_subdir/";
+ append_to_file
+ "$test_primary_datadir/tst_both_dir/both_subdir/both_file3",
+ "in both3";
+
+ RewindTest::create_standby($test_mode);
+
+ # Create different subdirs and files in primary and standby
+ my $test_standby_datadir = $node_standby->data_dir;
+
+ mkdir "$test_standby_datadir/tst_standby_dir";
+ append_to_file "$test_standby_datadir/tst_standby_dir/standby_file1",
+ "in standby1";
+ append_to_file "$test_standby_datadir/tst_standby_dir/standby_file2",
+ "in standby2";
+ append_to_file
+ "$test_standby_datadir/tst_standby_dir/standby_file3 with 'quotes'",
+ "in standby3";
+ mkdir "$test_standby_datadir/tst_standby_dir/standby_subdir/";
+ append_to_file
+ "$test_standby_datadir/tst_standby_dir/standby_subdir/standby_file4",
+ "in standby4";
+
+ mkdir "$test_primary_datadir/tst_primary_dir";
+ append_to_file "$test_primary_datadir/tst_primary_dir/primary_file1",
+ "in primary1";
+ append_to_file "$test_primary_datadir/tst_primary_dir/primary_file2",
+ "in primary2";
+ mkdir "$test_primary_datadir/tst_primary_dir/primary_subdir/";
+ append_to_file
+ "$test_primary_datadir/tst_primary_dir/primary_subdir/primary_file3",
+ "in primary3";
+
+ RewindTest::promote_standby();
+ RewindTest::run_pg_rewind($test_mode);
+
+ # List files in the data directory after rewind. All the files that
+ # were present in the standby should be present after rewind, and
+ # all the files that were added on the primary should be removed.
+ my @paths;
+ find(
+ sub {
+ push @paths, $File::Find::name
+ if $File::Find::name =~ m/.*tst_.*/;
+ },
+ $test_primary_datadir);
+ @paths = sort @paths;
+ is_deeply(
+ \@paths,
+ [
+ "$test_primary_datadir/tst_both_dir",
+ "$test_primary_datadir/tst_both_dir/both_file1",
+ "$test_primary_datadir/tst_both_dir/both_file2",
+ "$test_primary_datadir/tst_both_dir/both_subdir",
+ "$test_primary_datadir/tst_both_dir/both_subdir/both_file3",
+ "$test_primary_datadir/tst_standby_dir",
+ "$test_primary_datadir/tst_standby_dir/standby_file1",
+ "$test_primary_datadir/tst_standby_dir/standby_file2",
+ "$test_primary_datadir/tst_standby_dir/standby_file3 with 'quotes'",
+ "$test_primary_datadir/tst_standby_dir/standby_subdir",
+ "$test_primary_datadir/tst_standby_dir/standby_subdir/standby_file4"
+ ],
+ "file lists match");
+
+ RewindTest::clean_rewind_test();
+ return;
+}
+
+# Run the test in both modes.
+run_test('local');
+run_test('remote');
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl b/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl
new file mode 100644
index 0000000..5aafe58
--- /dev/null
+++ b/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl
@@ -0,0 +1,80 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+#
+# Test pg_rewind when the target's pg_wal directory is a symlink.
+#
+use strict;
+use warnings;
+use File::Copy;
+use File::Path qw(rmtree);
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use RewindTest;
+
+sub run_test
+{
+ my $test_mode = shift;
+
+ my $primary_xlogdir =
+ "${PostgreSQL::Test::Utils::tmp_check}/xlog_primary";
+
+ rmtree($primary_xlogdir);
+ RewindTest::setup_cluster($test_mode);
+
+ my $test_primary_datadir = $node_primary->data_dir;
+
+ # turn pg_wal into a symlink
+ print("moving $test_primary_datadir/pg_wal to $primary_xlogdir\n");
+ move("$test_primary_datadir/pg_wal", $primary_xlogdir) or die;
+ dir_symlink($primary_xlogdir, "$test_primary_datadir/pg_wal") or die;
+
+ RewindTest::start_primary();
+
+ # Create a test table and insert a row in primary.
+ primary_psql("CREATE TABLE tbl1 (d text)");
+ primary_psql("INSERT INTO tbl1 VALUES ('in primary')");
+
+ primary_psql("CHECKPOINT");
+
+ RewindTest::create_standby($test_mode);
+
+ # Insert additional data on primary that will be replicated to standby
+ primary_psql("INSERT INTO tbl1 values ('in primary, before promotion')");
+
+ primary_psql('CHECKPOINT');
+
+ RewindTest::promote_standby();
+
+ # Insert a row in the old primary. This causes the primary and standby
+ # to have "diverged", it's no longer possible to just apply the
+ # standy's logs over primary directory - you need to rewind.
+ primary_psql("INSERT INTO tbl1 VALUES ('in primary, after promotion')");
+
+ # Also insert a new row in the standby, which won't be present in the
+ # old primary.
+ standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");
+
+ RewindTest::run_pg_rewind($test_mode);
+
+ check_query(
+ 'SELECT * FROM tbl1',
+ qq(in primary
+in primary, before promotion
+in standby, after promotion
+),
+ 'table content');
+
+ RewindTest::clean_rewind_test();
+ return;
+}
+
+# Run the test in both modes
+run_test('local');
+run_test('remote');
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/005_same_timeline.pl b/src/bin/pg_rewind/t/005_same_timeline.pl
new file mode 100644
index 0000000..ffb62f9
--- /dev/null
+++ b/src/bin/pg_rewind/t/005_same_timeline.pl
@@ -0,0 +1,24 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+#
+# Test that running pg_rewind with the source and target clusters
+# on the same timeline runs successfully.
+#
+use strict;
+use warnings;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use RewindTest;
+
+RewindTest::setup_cluster();
+RewindTest::start_primary();
+RewindTest::create_standby();
+RewindTest::run_pg_rewind('local');
+RewindTest::clean_rewind_test();
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/006_options.pl b/src/bin/pg_rewind/t/006_options.pl
new file mode 100644
index 0000000..c3c27e9
--- /dev/null
+++ b/src/bin/pg_rewind/t/006_options.pl
@@ -0,0 +1,45 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+#
+# Test checking options of pg_rewind.
+#
+use strict;
+use warnings;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+program_help_ok('pg_rewind');
+program_version_ok('pg_rewind');
+program_options_handling_ok('pg_rewind');
+
+my $primary_pgdata = PostgreSQL::Test::Utils::tempdir;
+my $standby_pgdata = PostgreSQL::Test::Utils::tempdir;
+command_fails(
+ [
+ 'pg_rewind', '--debug',
+ '--target-pgdata', $primary_pgdata,
+ '--source-pgdata', $standby_pgdata,
+ 'extra_arg1'
+ ],
+ 'too many arguments');
+command_fails([ 'pg_rewind', '--target-pgdata', $primary_pgdata ],
+ 'no source specified');
+command_fails(
+ [
+ 'pg_rewind', '--debug',
+ '--target-pgdata', $primary_pgdata,
+ '--source-pgdata', $standby_pgdata,
+ '--source-server', 'incorrect_source'
+ ],
+ 'both remote and local sources specified');
+command_fails(
+ [
+ 'pg_rewind', '--debug',
+ '--target-pgdata', $primary_pgdata,
+ '--source-pgdata', $standby_pgdata,
+ '--write-recovery-conf'
+ ],
+ 'no local source with --write-recovery-conf');
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/007_standby_source.pl b/src/bin/pg_rewind/t/007_standby_source.pl
new file mode 100644
index 0000000..f89a4df
--- /dev/null
+++ b/src/bin/pg_rewind/t/007_standby_source.pl
@@ -0,0 +1,179 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+#
+# Test using a standby server as the source.
+#
+# This sets up three nodes: A, B and C. First, A is the primary,
+# B follows A, and C follows B:
+#
+# A (primary) <--- B (standby) <--- C (standby)
+#
+#
+# Then we promote C, and insert some divergent rows in A and C:
+#
+# A (primary) <--- B (standby) C (primary)
+#
+#
+# Finally, we run pg_rewind on C, to re-point it at B again:
+#
+# A (primary) <--- B (standby) <--- C (standby)
+#
+#
+# The test is similar to the basic tests, but since we're dealing with
+# three nodes, not two, we cannot use most of the RewindTest functions
+# as is.
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use FindBin;
+use lib $FindBin::RealBin;
+use File::Copy;
+use PostgreSQL::Test::Cluster;
+use RewindTest;
+
+my $tmp_folder = PostgreSQL::Test::Utils::tempdir;
+
+my $node_a;
+my $node_b;
+my $node_c;
+
+# Set up node A, as primary
+#
+# A (primary)
+
+setup_cluster('a');
+start_primary();
+$node_a = $node_primary;
+
+# Create a test table and insert a row in primary.
+$node_a->safe_psql('postgres', "CREATE TABLE tbl1 (d text)");
+$node_a->safe_psql('postgres', "INSERT INTO tbl1 VALUES ('in A')");
+primary_psql("CHECKPOINT");
+
+# Set up node B and C, as cascaded standbys
+#
+# A (primary) <--- B (standby) <--- C (standby)
+$node_a->backup('my_backup');
+$node_b = PostgreSQL::Test::Cluster->new('node_b');
+$node_b->init_from_backup($node_a, 'my_backup', has_streaming => 1);
+$node_b->set_standby_mode();
+$node_b->start;
+
+$node_b->backup('my_backup');
+$node_c = PostgreSQL::Test::Cluster->new('node_c');
+$node_c->init_from_backup($node_b, 'my_backup', has_streaming => 1);
+$node_c->set_standby_mode();
+$node_c->start;
+
+# Insert additional data on A, and wait for both standbys to catch up.
+$node_a->safe_psql('postgres',
+ "INSERT INTO tbl1 values ('in A, before promotion')");
+$node_a->safe_psql('postgres', 'CHECKPOINT');
+
+my $lsn = $node_a->lsn('write');
+$node_a->wait_for_catchup('node_b', 'write', $lsn);
+$node_b->wait_for_catchup('node_c', 'write', $lsn);
+
+# Promote C
+#
+# A (primary) <--- B (standby) C (primary)
+
+$node_c->promote;
+$node_c->safe_psql('postgres', "checkpoint");
+
+
+# Insert a row in A. This causes A/B and C to have "diverged", so that it's
+# no longer possible to just apply the standy's logs over primary directory
+# - you need to rewind.
+$node_a->safe_psql('postgres',
+ "INSERT INTO tbl1 VALUES ('in A, after C was promoted')");
+
+# make sure it's replicated to B before we continue
+$node_a->wait_for_catchup('node_b');
+
+# Also insert a new row in the standby, which won't be present in the
+# old primary.
+$node_c->safe_psql('postgres',
+ "INSERT INTO tbl1 VALUES ('in C, after C was promoted')");
+
+
+#
+# All set up. We're ready to run pg_rewind.
+#
+my $node_c_pgdata = $node_c->data_dir;
+
+# Stop the node and be ready to perform the rewind.
+$node_c->stop('fast');
+
+# Keep a temporary postgresql.conf or it would be overwritten during the rewind.
+copy(
+ "$node_c_pgdata/postgresql.conf",
+ "$tmp_folder/node_c-postgresql.conf.tmp");
+
+{
+ # Temporarily unset PGAPPNAME so that the server doesn't
+ # inherit it. Otherwise this could affect libpqwalreceiver
+ # connections in confusing ways.
+ local %ENV = %ENV;
+ delete $ENV{PGAPPNAME};
+
+ # Do rewind using a remote connection as source, generating
+ # recovery configuration automatically.
+ command_ok(
+ [
+ 'pg_rewind', "--debug",
+ "--source-server", $node_b->connstr('postgres'),
+ "--target-pgdata=$node_c_pgdata", "--no-sync",
+ "--write-recovery-conf"
+ ],
+ 'pg_rewind remote');
+}
+
+# Now move back postgresql.conf with old settings
+move(
+ "$tmp_folder/node_c-postgresql.conf.tmp",
+ "$node_c_pgdata/postgresql.conf");
+
+# Restart the node.
+$node_c->start;
+
+# set RewindTest::node_primary to point to the rewound node, so that we can
+# use check_query()
+$node_primary = $node_c;
+
+# Run some checks to verify that C has been successfully rewound,
+# and connected back to follow B.
+
+check_query(
+ 'SELECT * FROM tbl1',
+ qq(in A
+in A, before promotion
+in A, after C was promoted
+),
+ 'table content after rewind');
+
+# Insert another row, and observe that it's cascaded from A to B to C.
+$node_a->safe_psql('postgres',
+ "INSERT INTO tbl1 values ('in A, after rewind')");
+
+$node_b->wait_for_catchup('node_c', 'replay', $node_a->lsn('write'));
+
+check_query(
+ 'SELECT * FROM tbl1',
+ qq(in A
+in A, before promotion
+in A, after C was promoted
+in A, after rewind
+),
+ 'table content after rewind and insert');
+
+# clean up
+$node_a->teardown_node;
+$node_b->teardown_node;
+$node_c->teardown_node;
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/008_min_recovery_point.pl b/src/bin/pg_rewind/t/008_min_recovery_point.pl
new file mode 100644
index 0000000..e6a7177
--- /dev/null
+++ b/src/bin/pg_rewind/t/008_min_recovery_point.pl
@@ -0,0 +1,177 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+#
+# Test situation where a target data directory contains
+# WAL records beyond both the last checkpoint and the divergence
+# point:
+#
+# Target WAL (TLI 2):
+#
+# backup ... Checkpoint A ... INSERT 'rewind this'
+# (TLI 1 -> 2)
+#
+# ^ last common ^ minRecoveryPoint
+# checkpoint
+#
+# Source WAL (TLI 3):
+#
+# backup ... Checkpoint A ... Checkpoint B ... INSERT 'keep this'
+# (TLI 1 -> 2) (TLI 2 -> 3)
+#
+#
+# The last common checkpoint is Checkpoint A. But there is WAL on TLI 2
+# after the last common checkpoint that needs to be rewound. We used to
+# have a bug where minRecoveryPoint was ignored, and pg_rewind concluded
+# that the target doesn't need rewinding in this scenario, because the
+# last checkpoint on the target TLI was an ancestor of the source TLI.
+#
+#
+# This test does not make use of RewindTest as it requires three
+# nodes.
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use File::Copy;
+
+my $tmp_folder = PostgreSQL::Test::Utils::tempdir;
+
+my $node_1 = PostgreSQL::Test::Cluster->new('node_1');
+$node_1->init(allows_streaming => 1);
+$node_1->append_conf(
+ 'postgresql.conf', qq(
+wal_keep_size='100 MB'
+));
+
+$node_1->start;
+
+# Create a couple of test tables
+$node_1->safe_psql('postgres', 'CREATE TABLE public.foo (t TEXT)');
+$node_1->safe_psql('postgres', 'CREATE TABLE public.bar (t TEXT)');
+$node_1->safe_psql('postgres', "INSERT INTO public.bar VALUES ('in both')");
+
+#
+# Create node_2 and node_3 as standbys following node_1
+#
+my $backup_name = 'my_backup';
+$node_1->backup($backup_name);
+
+my $node_2 = PostgreSQL::Test::Cluster->new('node_2');
+$node_2->init_from_backup($node_1, $backup_name, has_streaming => 1);
+$node_2->start;
+
+my $node_3 = PostgreSQL::Test::Cluster->new('node_3');
+$node_3->init_from_backup($node_1, $backup_name, has_streaming => 1);
+$node_3->start;
+
+# Wait until node 3 has connected and caught up
+$node_1->wait_for_catchup('node_3');
+
+#
+# Swap the roles of node_1 and node_3, so that node_1 follows node_3.
+#
+$node_1->stop('fast');
+$node_3->promote;
+# Force a checkpoint after the promotion. pg_rewind looks at the control
+# file to determine what timeline the server is on, and that isn't updated
+# immediately at promotion, but only at the next checkpoint. When running
+# pg_rewind in remote mode, it's possible that we complete the test steps
+# after promotion so quickly that when pg_rewind runs, the standby has not
+# performed a checkpoint after promotion yet.
+$node_3->safe_psql('postgres', "checkpoint");
+
+# reconfigure node_1 as a standby following node_3
+my $node_3_connstr = $node_3->connstr;
+$node_1->append_conf(
+ 'postgresql.conf', qq(
+primary_conninfo='$node_3_connstr'
+));
+$node_1->set_standby_mode();
+$node_1->start();
+
+# also reconfigure node_2 to follow node_3
+$node_2->append_conf(
+ 'postgresql.conf', qq(
+primary_conninfo='$node_3_connstr'
+));
+$node_2->restart();
+
+#
+# Promote node_1, to create a split-brain scenario.
+#
+
+# make sure node_1 is full caught up with node_3 first
+$node_3->wait_for_catchup('node_1');
+
+$node_1->promote;
+# Force a checkpoint after promotion, like earlier.
+$node_1->safe_psql('postgres', "checkpoint");
+
+#
+# We now have a split-brain with two primaries. Insert a row on both to
+# demonstratively create a split brain. After the rewind, we should only
+# see the insert on 1, as the insert on node 3 is rewound away.
+#
+$node_1->safe_psql('postgres',
+ "INSERT INTO public.foo (t) VALUES ('keep this')");
+# 'bar' is unmodified in node 1, so it won't be overwritten by replaying the
+# WAL from node 1.
+$node_3->safe_psql('postgres',
+ "INSERT INTO public.bar (t) VALUES ('rewind this')");
+
+# Insert more rows in node 1, to bump up the XID counter. Otherwise, if
+# rewind doesn't correctly rewind the changes made on the other node,
+# we might fail to notice if the inserts are invisible because the XIDs
+# are not marked as committed.
+$node_1->safe_psql('postgres',
+ "INSERT INTO public.foo (t) VALUES ('and this')");
+$node_1->safe_psql('postgres',
+ "INSERT INTO public.foo (t) VALUES ('and this too')");
+
+# Wait for node 2 to catch up
+$node_2->poll_query_until('postgres',
+ q|SELECT COUNT(*) > 1 FROM public.bar|, 't');
+
+# At this point node_2 will shut down without a shutdown checkpoint,
+# but with WAL entries beyond the preceding shutdown checkpoint.
+$node_2->stop('fast');
+$node_3->stop('fast');
+
+my $node_2_pgdata = $node_2->data_dir;
+my $node_1_connstr = $node_1->connstr;
+
+# Keep a temporary postgresql.conf or it would be overwritten during the rewind.
+copy(
+ "$node_2_pgdata/postgresql.conf",
+ "$tmp_folder/node_2-postgresql.conf.tmp");
+
+command_ok(
+ [
+ 'pg_rewind', "--source-server=$node_1_connstr",
+ "--target-pgdata=$node_2_pgdata", "--debug"
+ ],
+ 'run pg_rewind');
+
+# Now move back postgresql.conf with old settings
+move(
+ "$tmp_folder/node_2-postgresql.conf.tmp",
+ "$node_2_pgdata/postgresql.conf");
+
+$node_2->start;
+
+# Check contents of the test tables after rewind. The rows inserted in node 3
+# before rewind should've been overwritten with the data from node 1.
+my $result;
+$result = $node_2->safe_psql('postgres', 'SELECT * FROM public.foo');
+is( $result, qq(keep this
+and this
+and this too), 'table foo after rewind');
+
+$result = $node_2->safe_psql('postgres', 'SELECT * FROM public.bar');
+is($result, qq(in both), 'table bar after rewind');
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/009_growing_files.pl b/src/bin/pg_rewind/t/009_growing_files.pl
new file mode 100644
index 0000000..9422828
--- /dev/null
+++ b/src/bin/pg_rewind/t/009_growing_files.pl
@@ -0,0 +1,77 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+use FindBin;
+use lib $FindBin::RealBin;
+
+use RewindTest;
+
+RewindTest::setup_cluster("local");
+RewindTest::start_primary();
+
+# Create a test table and insert a row in primary.
+primary_psql("CREATE TABLE tbl1 (d text)");
+primary_psql("INSERT INTO tbl1 VALUES ('in primary')");
+primary_psql("CHECKPOINT");
+
+RewindTest::create_standby("local");
+
+# Insert additional data on primary that will be replicated to standby
+primary_psql("INSERT INTO tbl1 values ('in primary, before promotion')");
+primary_psql('CHECKPOINT');
+
+RewindTest::promote_standby();
+
+# Insert a row in the old primary. This causes the primary and standby to have
+# "diverged", it's no longer possible to just apply the standy's logs over
+# primary directory - you need to rewind. Also insert a new row in the
+# standby, which won't be present in the old primary.
+primary_psql("INSERT INTO tbl1 VALUES ('in primary, after promotion')");
+standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");
+
+# Stop the nodes before running pg_rewind
+$node_standby->stop;
+$node_primary->stop;
+
+my $primary_pgdata = $node_primary->data_dir;
+my $standby_pgdata = $node_standby->data_dir;
+
+# Add an extra file that we can tamper with without interfering with the data
+# directory data files.
+mkdir "$standby_pgdata/tst_both_dir";
+append_to_file "$standby_pgdata/tst_both_dir/file1", 'a';
+
+# Run pg_rewind and pipe the output from the run into the extra file we want
+# to copy. This will ensure that the file is continuously growing during the
+# copy operation and the result will be an error.
+my $ret = run_log(
+ [
+ 'pg_rewind', '--debug',
+ '--source-pgdata', $standby_pgdata,
+ '--target-pgdata', $primary_pgdata,
+ '--no-sync',
+ ],
+ '2>>',
+ "$standby_pgdata/tst_both_dir/file1");
+ok(!$ret, 'Error out on copying growing file');
+
+# Ensure that the files are of different size, the final error message should
+# only be in one of them making them guaranteed to be different
+my $primary_size = -s "$primary_pgdata/tst_both_dir/file1";
+my $standby_size = -s "$standby_pgdata/tst_both_dir/file1";
+isnt($standby_size, $primary_size, "File sizes should differ");
+
+# Extract the last line from the verbose output as that should have the error
+# message for the unexpected file size
+my $last;
+open my $f, '<', "$standby_pgdata/tst_both_dir/file1";
+$last = $_ while (<$f>);
+close $f;
+like($last, qr/error: size of source file/, "Check error message");
+
+done_testing();
diff --git a/src/bin/pg_rewind/t/RewindTest.pm b/src/bin/pg_rewind/t/RewindTest.pm
new file mode 100644
index 0000000..98b66b0
--- /dev/null
+++ b/src/bin/pg_rewind/t/RewindTest.pm
@@ -0,0 +1,393 @@
+
+# Copyright (c) 2021-2022, PostgreSQL Global Development Group
+
+package RewindTest;
+
+# Test driver for pg_rewind. Each test consists of a cycle where a new cluster
+# is first created with initdb, and a streaming replication standby is set up
+# to follow the primary. Then the primary is shut down and the standby is
+# promoted, and finally pg_rewind is used to rewind the old primary, using the
+# standby as the source.
+#
+# To run a test, the test script (in t/ subdirectory) calls the functions
+# in this module. These functions should be called in this sequence:
+#
+# 1. setup_cluster - creates a PostgreSQL cluster that runs as the primary
+#
+# 2. start_primary - starts the primary server
+#
+# 3. create_standby - runs pg_basebackup to initialize a standby server, and
+# sets it up to follow the primary.
+#
+# 4. promote_standby - runs "pg_ctl promote" to promote the standby server.
+# The old primary keeps running.
+#
+# 5. run_pg_rewind - stops the old primary (if it's still running) and runs
+# pg_rewind to synchronize it with the now-promoted standby server.
+#
+# 6. clean_rewind_test - stops both servers used in the test, if they're
+# still running.
+#
+# The test script can use the helper functions primary_psql and standby_psql
+# to run psql against the primary and standby servers, respectively.
+
+use strict;
+use warnings;
+
+use Carp;
+use Exporter 'import';
+use File::Copy;
+use File::Path qw(rmtree);
+use IPC::Run qw(run);
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::RecursiveCopy;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+our @EXPORT = qw(
+ $node_primary
+ $node_standby
+
+ primary_psql
+ standby_psql
+ check_query
+
+ setup_cluster
+ start_primary
+ create_standby
+ promote_standby
+ run_pg_rewind
+ clean_rewind_test
+);
+
+# Our nodes.
+our $node_primary;
+our $node_standby;
+
+sub primary_psql
+{
+ my $cmd = shift;
+ my $dbname = shift || 'postgres';
+
+ system_or_bail 'psql', '-q', '--no-psqlrc', '-d',
+ $node_primary->connstr($dbname), '-c', "$cmd";
+ return;
+}
+
+sub standby_psql
+{
+ my $cmd = shift;
+ my $dbname = shift || 'postgres';
+
+ system_or_bail 'psql', '-q', '--no-psqlrc', '-d',
+ $node_standby->connstr($dbname), '-c', "$cmd";
+ return;
+}
+
+# Run a query against the primary, and check that the output matches what's
+# expected
+sub check_query
+{
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my ($query, $expected_stdout, $test_name) = @_;
+ my ($stdout, $stderr);
+
+ # we want just the output, no formatting
+ my $result = run [
+ 'psql', '-q', '-A', '-t', '--no-psqlrc', '-d',
+ $node_primary->connstr('postgres'),
+ '-c', $query
+ ],
+ '>', \$stdout, '2>', \$stderr;
+
+ is($result, 1, "$test_name: psql exit code");
+ is($stderr, '', "$test_name: psql no stderr");
+ is($stdout, $expected_stdout, "$test_name: query result matches");
+
+ return;
+}
+
+sub setup_cluster
+{
+ my $extra_name = shift; # Used to differentiate clusters
+ my $extra = shift; # Extra params for initdb
+
+ # Initialize primary, data checksums are mandatory
+ $node_primary =
+ PostgreSQL::Test::Cluster->new(
+ 'primary' . ($extra_name ? "_${extra_name}" : ''));
+
+ # Set up pg_hba.conf and pg_ident.conf for the role running
+ # pg_rewind. This role is used for all the tests, and has
+ # minimal permissions enough to rewind from an online source.
+ $node_primary->init(
+ allows_streaming => 1,
+ extra => $extra,
+ auth_extra => [ '--create-role', 'rewind_user' ]);
+
+ # Set wal_keep_size to prevent WAL segment recycling after enforced
+ # checkpoints in the tests.
+ $node_primary->append_conf(
+ 'postgresql.conf', qq(
+wal_keep_size = 320MB
+));
+ return;
+}
+
+sub start_primary
+{
+ $node_primary->start;
+
+ # Create custom role which is used to run pg_rewind, and adjust its
+ # permissions to the minimum necessary.
+ $node_primary->safe_psql(
+ 'postgres', "
+ CREATE ROLE rewind_user LOGIN;
+ GRANT EXECUTE ON function pg_catalog.pg_ls_dir(text, boolean, boolean)
+ TO rewind_user;
+ GRANT EXECUTE ON function pg_catalog.pg_stat_file(text, boolean)
+ TO rewind_user;
+ GRANT EXECUTE ON function pg_catalog.pg_read_binary_file(text)
+ TO rewind_user;
+ GRANT EXECUTE ON function pg_catalog.pg_read_binary_file(text, bigint, bigint, boolean)
+ TO rewind_user;");
+
+ #### Now run the test-specific parts to initialize the primary before setting
+ # up standby
+
+ return;
+}
+
+sub create_standby
+{
+ my $extra_name = shift;
+
+ $node_standby =
+ PostgreSQL::Test::Cluster->new(
+ 'standby' . ($extra_name ? "_${extra_name}" : ''));
+ $node_primary->backup('my_backup');
+ $node_standby->init_from_backup($node_primary, 'my_backup');
+ my $connstr_primary = $node_primary->connstr();
+
+ $node_standby->append_conf(
+ "postgresql.conf", qq(
+primary_conninfo='$connstr_primary'
+));
+
+ $node_standby->set_standby_mode();
+
+ # Start standby
+ $node_standby->start;
+
+ # The standby may have WAL to apply before it matches the primary. That
+ # is fine, because no test examines the standby before promotion.
+
+ return;
+}
+
+sub promote_standby
+{
+ #### Now run the test-specific parts to run after standby has been started
+ # up standby
+
+ # Wait for the standby to receive and write all WAL.
+ $node_primary->wait_for_catchup($node_standby, 'write');
+
+ # Now promote standby and insert some new data on primary, this will put
+ # the primary out-of-sync with the standby.
+ $node_standby->promote;
+
+ # Force a checkpoint after the promotion. pg_rewind looks at the control
+ # file to determine what timeline the server is on, and that isn't updated
+ # immediately at promotion, but only at the next checkpoint. When running
+ # pg_rewind in remote mode, it's possible that we complete the test steps
+ # after promotion so quickly that when pg_rewind runs, the standby has not
+ # performed a checkpoint after promotion yet.
+ standby_psql("checkpoint");
+
+ return;
+}
+
+sub run_pg_rewind
+{
+ my $test_mode = shift;
+ my $primary_pgdata = $node_primary->data_dir;
+ my $standby_pgdata = $node_standby->data_dir;
+ my $standby_connstr = $node_standby->connstr('postgres');
+ my $tmp_folder = PostgreSQL::Test::Utils::tempdir;
+
+ # Append the rewind-specific role to the connection string.
+ $standby_connstr = "$standby_connstr user=rewind_user";
+
+ if ($test_mode eq 'archive')
+ {
+ # pg_rewind is tested with --restore-target-wal by moving all
+ # WAL files to a secondary location. Note that this leads to
+ # a failure in ensureCleanShutdown(), forcing to the use of
+ # --no-ensure-shutdown in this mode as the initial set of WAL
+ # files needed to ensure a clean restart is gone. This could
+ # be improved by keeping around only a minimum set of WAL
+ # segments but that would just make the test more costly,
+ # without improving the coverage. Hence, instead, stop
+ # gracefully the primary here.
+ $node_primary->stop;
+ }
+ else
+ {
+ # Stop the primary and be ready to perform the rewind. The cluster
+ # needs recovery to finish once, and pg_rewind makes sure that it
+ # happens automatically.
+ $node_primary->stop('immediate');
+ }
+
+ # At this point, the rewind processing is ready to run.
+ # We now have a very simple scenario with a few diverged WAL record.
+ # The real testing begins really now with a bifurcation of the possible
+ # scenarios that pg_rewind supports.
+
+ # Keep a temporary postgresql.conf for primary node or it would be
+ # overwritten during the rewind.
+ copy(
+ "$primary_pgdata/postgresql.conf",
+ "$tmp_folder/primary-postgresql.conf.tmp");
+
+ # Now run pg_rewind
+ if ($test_mode eq "local")
+ {
+
+ # Do rewind using a local pgdata as source
+ # Stop the primary and be ready to perform the rewind
+ $node_standby->stop;
+ command_ok(
+ [
+ 'pg_rewind',
+ "--debug",
+ "--source-pgdata=$standby_pgdata",
+ "--target-pgdata=$primary_pgdata",
+ "--no-sync",
+ "--config-file",
+ "$tmp_folder/primary-postgresql.conf.tmp"
+ ],
+ 'pg_rewind local');
+ }
+ elsif ($test_mode eq "remote")
+ {
+ # Do rewind using a remote connection as source, generating
+ # recovery configuration automatically.
+ command_ok(
+ [
+ 'pg_rewind', "--debug",
+ "--source-server", $standby_connstr,
+ "--target-pgdata=$primary_pgdata", "--no-sync",
+ "--write-recovery-conf", "--config-file",
+ "$tmp_folder/primary-postgresql.conf.tmp"
+ ],
+ 'pg_rewind remote');
+
+ # Check that standby.signal is here as recovery configuration
+ # was requested.
+ ok( -e "$primary_pgdata/standby.signal",
+ 'standby.signal created after pg_rewind');
+
+ # Now, when pg_rewind apparently succeeded with minimal permissions,
+ # add REPLICATION privilege. So we could test that new standby
+ # is able to connect to the new primary with generated config.
+ $node_standby->safe_psql('postgres',
+ "ALTER ROLE rewind_user WITH REPLICATION;");
+ }
+ elsif ($test_mode eq "archive")
+ {
+
+ # Do rewind using a local pgdata as source and specified
+ # directory with target WAL archive. The old primary has
+ # to be stopped at this point.
+
+ # Remove the existing archive directory and move all WAL
+ # segments from the old primary to the archives. These
+ # will be used by pg_rewind.
+ rmtree($node_primary->archive_dir);
+ PostgreSQL::Test::RecursiveCopy::copypath(
+ $node_primary->data_dir . "/pg_wal",
+ $node_primary->archive_dir);
+
+ # Fast way to remove entire directory content
+ rmtree($node_primary->data_dir . "/pg_wal");
+ mkdir($node_primary->data_dir . "/pg_wal");
+
+ # Make sure that directories have the right umask as this is
+ # required by a follow-up check on permissions, and better
+ # safe than sorry.
+ chmod(0700, $node_primary->archive_dir);
+ chmod(0700, $node_primary->data_dir . "/pg_wal");
+
+ # Add appropriate restore_command to the target cluster
+ $node_primary->enable_restoring($node_primary, 0);
+
+ # Stop the new primary and be ready to perform the rewind.
+ $node_standby->stop;
+
+ # Note the use of --no-ensure-shutdown here. WAL files are
+ # gone in this mode and the primary has been stopped
+ # gracefully already. --config-file reuses the original
+ # postgresql.conf as restore_command has been enabled above.
+ command_ok(
+ [
+ 'pg_rewind',
+ "--debug",
+ "--source-pgdata=$standby_pgdata",
+ "--target-pgdata=$primary_pgdata",
+ "--no-sync",
+ "--no-ensure-shutdown",
+ "--restore-target-wal",
+ "--config-file",
+ "$primary_pgdata/postgresql.conf"
+ ],
+ 'pg_rewind archive');
+ }
+ else
+ {
+
+ # Cannot come here normally
+ croak("Incorrect test mode specified");
+ }
+
+ # Now move back postgresql.conf with old settings
+ move(
+ "$tmp_folder/primary-postgresql.conf.tmp",
+ "$primary_pgdata/postgresql.conf");
+
+ chmod(
+ $node_primary->group_access() ? 0640 : 0600,
+ "$primary_pgdata/postgresql.conf")
+ or BAIL_OUT(
+ "unable to set permissions for $primary_pgdata/postgresql.conf");
+
+ # Plug-in rewound node to the now-promoted standby node
+ if ($test_mode ne "remote")
+ {
+ my $port_standby = $node_standby->port;
+ $node_primary->append_conf(
+ 'postgresql.conf', qq(
+primary_conninfo='port=$port_standby'));
+
+ $node_primary->set_standby_mode();
+ }
+
+ # Restart the primary to check that rewind went correctly
+ $node_primary->start;
+
+ #### Now run the test-specific parts to check the result
+
+ return;
+}
+
+# Clean up after the test. Stop both servers, if they're still running.
+sub clean_rewind_test
+{
+ $node_primary->teardown_node if defined $node_primary;
+ $node_standby->teardown_node if defined $node_standby;
+ return;
+}
+
+1;
diff --git a/src/bin/pg_rewind/timeline.c b/src/bin/pg_rewind/timeline.c
new file mode 100644
index 0000000..983388c
--- /dev/null
+++ b/src/bin/pg_rewind/timeline.c
@@ -0,0 +1,130 @@
+/*-------------------------------------------------------------------------
+ *
+ * timeline.c
+ * timeline-related functions.
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include "access/timeline.h"
+#include "access/xlog_internal.h"
+#include "pg_rewind.h"
+
+/*
+ * This is copy-pasted from the backend readTimeLineHistory, modified to
+ * return a malloc'd array and to work without backend functions.
+ */
+/*
+ * Try to read a timeline's history file.
+ *
+ * If successful, return the list of component TLIs (the given TLI followed by
+ * its ancestor TLIs). If we can't find the history file, assume that the
+ * timeline has no parents, and return a list of just the specified timeline
+ * ID.
+ */
+TimeLineHistoryEntry *
+rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
+{
+ char *fline;
+ TimeLineHistoryEntry *entry;
+ TimeLineHistoryEntry *entries = NULL;
+ int nlines = 0;
+ TimeLineID lasttli = 0;
+ XLogRecPtr prevend;
+ char *bufptr;
+ bool lastline = false;
+
+ /*
+ * Parse the file...
+ */
+ prevend = InvalidXLogRecPtr;
+ bufptr = buffer;
+ while (!lastline)
+ {
+ char *ptr;
+ TimeLineID tli;
+ uint32 switchpoint_hi;
+ uint32 switchpoint_lo;
+ int nfields;
+
+ fline = bufptr;
+ while (*bufptr && *bufptr != '\n')
+ bufptr++;
+ if (!(*bufptr))
+ lastline = true;
+ else
+ *bufptr++ = '\0';
+
+ /* skip leading whitespace and check for # comment */
+ for (ptr = fline; *ptr; ptr++)
+ {
+ if (!isspace((unsigned char) *ptr))
+ break;
+ }
+ if (*ptr == '\0' || *ptr == '#')
+ continue;
+
+ nfields = sscanf(fline, "%u\t%X/%X", &tli, &switchpoint_hi, &switchpoint_lo);
+
+ if (nfields < 1)
+ {
+ /* expect a numeric timeline ID as first field of line */
+ pg_log_error("syntax error in history file: %s", fline);
+ pg_log_error_detail("Expected a numeric timeline ID.");
+ exit(1);
+ }
+ if (nfields != 3)
+ {
+ pg_log_error("syntax error in history file: %s", fline);
+ pg_log_error_detail("Expected a write-ahead log switchpoint location.");
+ exit(1);
+ }
+ if (entries && tli <= lasttli)
+ {
+ pg_log_error("invalid data in history file: %s", fline);
+ pg_log_error_detail("Timeline IDs must be in increasing sequence.");
+ exit(1);
+ }
+
+ lasttli = tli;
+
+ nlines++;
+ entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
+
+ entry = &entries[nlines - 1];
+ entry->tli = tli;
+ entry->begin = prevend;
+ entry->end = ((uint64) (switchpoint_hi)) << 32 | (uint64) switchpoint_lo;
+ prevend = entry->end;
+
+ /* we ignore the remainder of each line */
+ }
+
+ if (entries && targetTLI <= lasttli)
+ {
+ pg_log_error("invalid data in history file");
+ pg_log_error_detail("Timeline IDs must be less than child timeline's ID.");
+ exit(1);
+ }
+
+ /*
+ * Create one more entry for the "tip" of the timeline, which has no entry
+ * in the history file.
+ */
+ nlines++;
+ if (entries)
+ entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
+ else
+ entries = pg_malloc(1 * sizeof(TimeLineHistoryEntry));
+
+ entry = &entries[nlines - 1];
+ entry->tli = targetTLI;
+ entry->begin = prevend;
+ entry->end = InvalidXLogRecPtr;
+
+ *nentries = nlines;
+ return entries;
+}