diff options
Diffstat (limited to 'src/bin/pg_amcheck')
-rw-r--r-- | src/bin/pg_amcheck/.gitignore | 3 | ||||
-rw-r--r-- | src/bin/pg_amcheck/Makefile | 51 | ||||
-rw-r--r-- | src/bin/pg_amcheck/README | 19 | ||||
-rw-r--r-- | src/bin/pg_amcheck/nls.mk | 12 | ||||
-rw-r--r-- | src/bin/pg_amcheck/pg_amcheck.c | 2216 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/de.po | 523 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/el.po | 516 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/es.po | 523 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/fr.po | 575 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/ja.po | 527 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/ru.po | 591 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/sv.po | 520 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/uk.po | 506 | ||||
-rw-r--r-- | src/bin/pg_amcheck/po/zh_CN.po | 500 | ||||
-rw-r--r-- | src/bin/pg_amcheck/t/001_basic.pl | 12 | ||||
-rw-r--r-- | src/bin/pg_amcheck/t/002_nonesuch.pl | 359 | ||||
-rw-r--r-- | src/bin/pg_amcheck/t/003_check.pl | 518 | ||||
-rw-r--r-- | src/bin/pg_amcheck/t/004_verify_heapam.pl | 529 | ||||
-rw-r--r-- | src/bin/pg_amcheck/t/005_opclass_damage.pl | 59 |
19 files changed, 8559 insertions, 0 deletions
diff --git a/src/bin/pg_amcheck/.gitignore b/src/bin/pg_amcheck/.gitignore new file mode 100644 index 0000000..c21a14d --- /dev/null +++ b/src/bin/pg_amcheck/.gitignore @@ -0,0 +1,3 @@ +pg_amcheck + +/tmp_check/ diff --git a/src/bin/pg_amcheck/Makefile b/src/bin/pg_amcheck/Makefile new file mode 100644 index 0000000..6192523 --- /dev/null +++ b/src/bin/pg_amcheck/Makefile @@ -0,0 +1,51 @@ +#------------------------------------------------------------------------- +# +# Makefile for src/bin/pg_amcheck +# +# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/bin/pg_amcheck/Makefile +# +#------------------------------------------------------------------------- + +PGFILEDESC = "pg_amcheck - detect corruption within database relations" +PGAPPICON=win32 + +EXTRA_INSTALL=contrib/amcheck contrib/pageinspect + +subdir = src/bin/pg_amcheck +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS) +LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) + +OBJS = \ + $(WIN32RES) \ + pg_amcheck.o + +all: pg_amcheck + +pg_amcheck: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils + $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) + + +install: all installdirs + $(INSTALL_PROGRAM) pg_amcheck$(X) '$(DESTDIR)$(bindir)/pg_amcheck$(X)' + +installdirs: + $(MKDIR_P) '$(DESTDIR)$(bindir)' + +uninstall: + rm -f '$(DESTDIR)$(bindir)/pg_amcheck$(X)' + +clean distclean maintainer-clean: + rm -f pg_amcheck$(X) $(OBJS) + rm -rf tmp_check + +check: + $(prove_check) + +installcheck: + $(prove_installcheck) diff --git a/src/bin/pg_amcheck/README b/src/bin/pg_amcheck/README new file mode 100644 index 0000000..950f8a7 --- /dev/null +++ b/src/bin/pg_amcheck/README @@ -0,0 +1,19 @@ +src/bin/pg_amcheck/README + +pg_amcheck is a command-line tool for running the amcheck extension. + +Running the regression tests +============================ + +NOTE: You must have given the --enable-tap-tests argument to configure. +Also, to use "make installcheck", you must have built and installed +contrib/amcheck and contrib/pageinspect in addition to the core code. + +Run + make check +or + make installcheck +You can use "make installcheck" if you previously did "make install". +In that case, the code in the installation tree is tested. With +"make check", a temporary installation tree is built from the current +sources and then tested. diff --git a/src/bin/pg_amcheck/nls.mk b/src/bin/pg_amcheck/nls.mk new file mode 100644 index 0000000..e8b71ce --- /dev/null +++ b/src/bin/pg_amcheck/nls.mk @@ -0,0 +1,12 @@ +# src/bin/pg_amcheck/nls.mk +CATALOG_NAME = pg_amcheck +AVAIL_LANGUAGES = de el es fr ja ru sv uk zh_CN +GETTEXT_FILES = $(FRONTEND_COMMON_GETTEXT_FILES) \ + pg_amcheck.c \ + ../../fe_utils/cancel.c \ + ../../fe_utils/connect_utils.c \ + ../../fe_utils/query_utils.c +GETTEXT_TRIGGERS = $(FRONTEND_COMMON_GETTEXT_TRIGGERS) \ + log_no_match +GETTEXT_FLAGS = $(FRONTEND_COMMON_GETTEXT_FLAGS) \ + log_no_match:1:c-format diff --git a/src/bin/pg_amcheck/pg_amcheck.c b/src/bin/pg_amcheck/pg_amcheck.c new file mode 100644 index 0000000..2c86dda --- /dev/null +++ b/src/bin/pg_amcheck/pg_amcheck.c @@ -0,0 +1,2216 @@ +/*------------------------------------------------------------------------- + * + * pg_amcheck.c + * Detects corruption within database relations. + * + * Copyright (c) 2017-2021, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/bin/pg_amcheck/pg_amcheck.c + * + *------------------------------------------------------------------------- + */ +#include "postgres_fe.h" + +#include <time.h> + +#include "catalog/pg_am_d.h" +#include "catalog/pg_namespace_d.h" +#include "common/logging.h" +#include "common/username.h" +#include "fe_utils/cancel.h" +#include "fe_utils/option_utils.h" +#include "fe_utils/parallel_slot.h" +#include "fe_utils/query_utils.h" +#include "fe_utils/simple_list.h" +#include "fe_utils/string_utils.h" +#include "getopt_long.h" /* pgrminclude ignore */ +#include "pgtime.h" +#include "storage/block.h" + +typedef struct PatternInfo +{ + const char *pattern; /* Unaltered pattern from the command line */ + char *db_regex; /* Database regexp parsed from pattern, or + * NULL */ + char *nsp_regex; /* Schema regexp parsed from pattern, or NULL */ + char *rel_regex; /* Relation regexp parsed from pattern, or + * NULL */ + bool heap_only; /* true if rel_regex should only match heap + * tables */ + bool btree_only; /* true if rel_regex should only match btree + * indexes */ + bool matched; /* true if the pattern matched in any database */ +} PatternInfo; + +typedef struct PatternInfoArray +{ + PatternInfo *data; + size_t len; +} PatternInfoArray; + +/* pg_amcheck command line options controlled by user flags */ +typedef struct AmcheckOptions +{ + bool dbpattern; + bool alldb; + bool echo; + bool verbose; + bool strict_names; + bool show_progress; + int jobs; + + /* + * Whether to install missing extensions, and optionally the name of the + * schema in which to install the extension's objects. + */ + bool install_missing; + char *install_schema; + + /* Objects to check or not to check, as lists of PatternInfo structs. */ + PatternInfoArray include; + PatternInfoArray exclude; + + /* + * As an optimization, if any pattern in the exclude list applies to heap + * tables, or similarly if any such pattern applies to btree indexes, or + * to schemas, then these will be true, otherwise false. These should + * always agree with what you'd conclude by grep'ing through the exclude + * list. + */ + bool excludetbl; + bool excludeidx; + bool excludensp; + + /* + * If any inclusion pattern exists, then we should only be checking + * matching relations rather than all relations, so this is true iff + * include is empty. + */ + bool allrel; + + /* heap table checking options */ + bool no_toast_expansion; + bool reconcile_toast; + bool on_error_stop; + int64 startblock; + int64 endblock; + const char *skip; + + /* btree index checking options */ + bool parent_check; + bool rootdescend; + bool heapallindexed; + + /* heap and btree hybrid option */ + bool no_btree_expansion; +} AmcheckOptions; + +static AmcheckOptions opts = { + .dbpattern = false, + .alldb = false, + .echo = false, + .verbose = false, + .strict_names = true, + .show_progress = false, + .jobs = 1, + .install_missing = false, + .install_schema = "pg_catalog", + .include = {NULL, 0}, + .exclude = {NULL, 0}, + .excludetbl = false, + .excludeidx = false, + .excludensp = false, + .allrel = true, + .no_toast_expansion = false, + .reconcile_toast = true, + .on_error_stop = false, + .startblock = -1, + .endblock = -1, + .skip = "none", + .parent_check = false, + .rootdescend = false, + .heapallindexed = false, + .no_btree_expansion = false +}; + +static const char *progname = NULL; + +/* Whether all relations have so far passed their corruption checks */ +static bool all_checks_pass = true; + +/* Time last progress report was displayed */ +static pg_time_t last_progress_report = 0; +static bool progress_since_last_stderr = false; + +typedef struct DatabaseInfo +{ + char *datname; + char *amcheck_schema; /* escaped, quoted literal */ +} DatabaseInfo; + +typedef struct RelationInfo +{ + const DatabaseInfo *datinfo; /* shared by other relinfos */ + Oid reloid; + bool is_heap; /* true if heap, false if btree */ + char *nspname; + char *relname; + int relpages; + int blocks_to_check; + char *sql; /* set during query run, pg_free'd after */ +} RelationInfo; + +/* + * Query for determining if contrib's amcheck is installed. If so, selects the + * namespace name where amcheck's functions can be found. + */ +static const char *amcheck_sql = +"SELECT n.nspname, x.extversion FROM pg_catalog.pg_extension x" +"\nJOIN pg_catalog.pg_namespace n ON x.extnamespace = n.oid" +"\nWHERE x.extname = 'amcheck'"; + +static void prepare_heap_command(PQExpBuffer sql, RelationInfo *rel, + PGconn *conn); +static void prepare_btree_command(PQExpBuffer sql, RelationInfo *rel, + PGconn *conn); +static void run_command(ParallelSlot *slot, const char *sql); +static bool verify_heap_slot_handler(PGresult *res, PGconn *conn, + void *context); +static bool verify_btree_slot_handler(PGresult *res, PGconn *conn, void *context); +static void help(const char *progname); +static void progress_report(uint64 relations_total, uint64 relations_checked, + uint64 relpages_total, uint64 relpages_checked, + const char *datname, bool force, bool finished); + +static void append_database_pattern(PatternInfoArray *pia, const char *pattern, + int encoding); +static void append_schema_pattern(PatternInfoArray *pia, const char *pattern, + int encoding); +static void append_relation_pattern(PatternInfoArray *pia, const char *pattern, + int encoding); +static void append_heap_pattern(PatternInfoArray *pia, const char *pattern, + int encoding); +static void append_btree_pattern(PatternInfoArray *pia, const char *pattern, + int encoding); +static void compile_database_list(PGconn *conn, SimplePtrList *databases, + const char *initial_dbname); +static void compile_relation_list_one_db(PGconn *conn, SimplePtrList *relations, + const DatabaseInfo *datinfo, + uint64 *pagecount); + +#define log_no_match(...) do { \ + if (opts.strict_names) \ + pg_log_generic(PG_LOG_ERROR, __VA_ARGS__); \ + else \ + pg_log_generic(PG_LOG_WARNING, __VA_ARGS__); \ + } while(0) + +#define FREE_AND_SET_NULL(x) do { \ + pg_free(x); \ + (x) = NULL; \ + } while (0) + +int +main(int argc, char *argv[]) +{ + PGconn *conn = NULL; + SimplePtrListCell *cell; + SimplePtrList databases = {NULL, NULL}; + SimplePtrList relations = {NULL, NULL}; + bool failed = false; + const char *latest_datname; + int parallel_workers; + ParallelSlotArray *sa; + PQExpBufferData sql; + uint64 reltotal = 0; + uint64 pageschecked = 0; + uint64 pagestotal = 0; + uint64 relprogress = 0; + int pattern_id; + + static struct option long_options[] = { + /* Connection options */ + {"host", required_argument, NULL, 'h'}, + {"port", required_argument, NULL, 'p'}, + {"username", required_argument, NULL, 'U'}, + {"no-password", no_argument, NULL, 'w'}, + {"password", no_argument, NULL, 'W'}, + {"maintenance-db", required_argument, NULL, 1}, + + /* check options */ + {"all", no_argument, NULL, 'a'}, + {"database", required_argument, NULL, 'd'}, + {"exclude-database", required_argument, NULL, 'D'}, + {"echo", no_argument, NULL, 'e'}, + {"index", required_argument, NULL, 'i'}, + {"exclude-index", required_argument, NULL, 'I'}, + {"jobs", required_argument, NULL, 'j'}, + {"progress", no_argument, NULL, 'P'}, + {"relation", required_argument, NULL, 'r'}, + {"exclude-relation", required_argument, NULL, 'R'}, + {"schema", required_argument, NULL, 's'}, + {"exclude-schema", required_argument, NULL, 'S'}, + {"table", required_argument, NULL, 't'}, + {"exclude-table", required_argument, NULL, 'T'}, + {"verbose", no_argument, NULL, 'v'}, + {"no-dependent-indexes", no_argument, NULL, 2}, + {"no-dependent-toast", no_argument, NULL, 3}, + {"exclude-toast-pointers", no_argument, NULL, 4}, + {"on-error-stop", no_argument, NULL, 5}, + {"skip", required_argument, NULL, 6}, + {"startblock", required_argument, NULL, 7}, + {"endblock", required_argument, NULL, 8}, + {"rootdescend", no_argument, NULL, 9}, + {"no-strict-names", no_argument, NULL, 10}, + {"heapallindexed", no_argument, NULL, 11}, + {"parent-check", no_argument, NULL, 12}, + {"install-missing", optional_argument, NULL, 13}, + + {NULL, 0, NULL, 0} + }; + + int optindex; + int c; + + const char *db = NULL; + const char *maintenance_db = NULL; + + const char *host = NULL; + const char *port = NULL; + const char *username = NULL; + enum trivalue prompt_password = TRI_DEFAULT; + int encoding = pg_get_encoding_from_locale(NULL, false); + ConnParams cparams; + + pg_logging_init(argv[0]); + progname = get_progname(argv[0]); + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_amcheck")); + + handle_help_version_opts(argc, argv, progname, help); + + /* process command-line options */ + while ((c = getopt_long(argc, argv, "ad:D:eh:Hi:I:j:p:Pr:R:s:S:t:T:U:wWv", + long_options, &optindex)) != -1) + { + char *endptr; + unsigned long optval; + + switch (c) + { + case 'a': + opts.alldb = true; + break; + case 'd': + opts.dbpattern = true; + append_database_pattern(&opts.include, optarg, encoding); + break; + case 'D': + opts.dbpattern = true; + append_database_pattern(&opts.exclude, optarg, encoding); + break; + case 'e': + opts.echo = true; + break; + case 'h': + host = pg_strdup(optarg); + break; + case 'i': + opts.allrel = false; + append_btree_pattern(&opts.include, optarg, encoding); + break; + case 'I': + opts.excludeidx = true; + append_btree_pattern(&opts.exclude, optarg, encoding); + break; + case 'j': + opts.jobs = atoi(optarg); + if (opts.jobs < 1) + { + pg_log_error("number of parallel jobs must be at least 1"); + exit(1); + } + break; + case 'p': + port = pg_strdup(optarg); + break; + case 'P': + opts.show_progress = true; + break; + case 'r': + opts.allrel = false; + append_relation_pattern(&opts.include, optarg, encoding); + break; + case 'R': + opts.excludeidx = true; + opts.excludetbl = true; + append_relation_pattern(&opts.exclude, optarg, encoding); + break; + case 's': + opts.allrel = false; + append_schema_pattern(&opts.include, optarg, encoding); + break; + case 'S': + opts.excludensp = true; + append_schema_pattern(&opts.exclude, optarg, encoding); + break; + case 't': + opts.allrel = false; + append_heap_pattern(&opts.include, optarg, encoding); + break; + case 'T': + opts.excludetbl = true; + append_heap_pattern(&opts.exclude, optarg, encoding); + break; + case 'U': + username = pg_strdup(optarg); + break; + case 'w': + prompt_password = TRI_NO; + break; + case 'W': + prompt_password = TRI_YES; + break; + case 'v': + opts.verbose = true; + pg_logging_increase_verbosity(); + break; + case 1: + maintenance_db = pg_strdup(optarg); + break; + case 2: + opts.no_btree_expansion = true; + break; + case 3: + opts.no_toast_expansion = true; + break; + case 4: + opts.reconcile_toast = false; + break; + case 5: + opts.on_error_stop = true; + break; + case 6: + if (pg_strcasecmp(optarg, "all-visible") == 0) + opts.skip = "all-visible"; + else if (pg_strcasecmp(optarg, "all-frozen") == 0) + opts.skip = "all-frozen"; + else if (pg_strcasecmp(optarg, "none") == 0) + opts.skip = "none"; + else + { + pg_log_error("invalid argument for option %s", "--skip"); + exit(1); + } + break; + case 7: + errno = 0; + optval = strtoul(optarg, &endptr, 10); + if (endptr == optarg || *endptr != '\0' || errno != 0) + { + pg_log_error("invalid start block"); + exit(1); + } + if (optval > MaxBlockNumber) + { + pg_log_error("start block out of bounds"); + exit(1); + } + opts.startblock = optval; + break; + case 8: + errno = 0; + optval = strtoul(optarg, &endptr, 10); + if (endptr == optarg || *endptr != '\0' || errno != 0) + { + pg_log_error("invalid end block"); + exit(1); + } + if (optval > MaxBlockNumber) + { + pg_log_error("end block out of bounds"); + exit(1); + } + opts.endblock = optval; + break; + case 9: + opts.rootdescend = true; + opts.parent_check = true; + break; + case 10: + opts.strict_names = false; + break; + case 11: + opts.heapallindexed = true; + break; + case 12: + opts.parent_check = true; + break; + case 13: + opts.install_missing = true; + if (optarg) + opts.install_schema = pg_strdup(optarg); + break; + default: + fprintf(stderr, + _("Try \"%s --help\" for more information.\n"), + progname); + exit(1); + } + } + + if (opts.endblock >= 0 && opts.endblock < opts.startblock) + { + pg_log_error("end block precedes start block"); + exit(1); + } + + /* + * A single non-option arguments specifies a database name or connection + * string. + */ + if (optind < argc) + { + db = argv[optind]; + optind++; + } + + if (optind < argc) + { + pg_log_error("too many command-line arguments (first is \"%s\")", + argv[optind]); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + exit(1); + } + + /* fill cparams except for dbname, which is set below */ + cparams.pghost = host; + cparams.pgport = port; + cparams.pguser = username; + cparams.prompt_password = prompt_password; + cparams.dbname = NULL; + cparams.override_dbname = NULL; + + setup_cancel_handler(NULL); + + /* choose the database for our initial connection */ + if (opts.alldb) + { + if (db != NULL) + { + pg_log_error("cannot specify a database name with --all"); + exit(1); + } + cparams.dbname = maintenance_db; + } + else if (db != NULL) + { + if (opts.dbpattern) + { + pg_log_error("cannot specify both a database name and database patterns"); + exit(1); + } + cparams.dbname = db; + } + + if (opts.alldb || opts.dbpattern) + { + conn = connectMaintenanceDatabase(&cparams, progname, opts.echo); + compile_database_list(conn, &databases, NULL); + } + else + { + if (cparams.dbname == NULL) + { + if (getenv("PGDATABASE")) + cparams.dbname = getenv("PGDATABASE"); + else if (getenv("PGUSER")) + cparams.dbname = getenv("PGUSER"); + else + cparams.dbname = get_user_name_or_exit(progname); + } + conn = connectDatabase(&cparams, progname, opts.echo, false, true); + compile_database_list(conn, &databases, PQdb(conn)); + } + + if (databases.head == NULL) + { + if (conn != NULL) + disconnectDatabase(conn); + pg_log_error("no databases to check"); + exit(0); + } + + /* + * Compile a list of all relations spanning all databases to be checked. + */ + for (cell = databases.head; cell; cell = cell->next) + { + PGresult *result; + int ntups; + const char *amcheck_schema = NULL; + DatabaseInfo *dat = (DatabaseInfo *) cell->ptr; + + cparams.override_dbname = dat->datname; + if (conn == NULL || strcmp(PQdb(conn), dat->datname) != 0) + { + if (conn != NULL) + disconnectDatabase(conn); + conn = connectDatabase(&cparams, progname, opts.echo, false, true); + } + + /* + * Optionally install amcheck if not already installed in this + * database. + */ + if (opts.install_missing) + { + char *schema; + char *install_sql; + + /* + * Must re-escape the schema name for each database, as the + * escaping rules may change. + */ + schema = PQescapeIdentifier(conn, opts.install_schema, + strlen(opts.install_schema)); + install_sql = psprintf("CREATE EXTENSION IF NOT EXISTS amcheck WITH SCHEMA %s", + schema); + + executeCommand(conn, install_sql, opts.echo); + pfree(install_sql); + pfree(schema); + } + + /* + * Verify that amcheck is installed for this next database. User + * error could result in a database not having amcheck that should + * have it, but we also could be iterating over multiple databases + * where not all of them have amcheck installed (for example, + * 'template1'). + */ + result = executeQuery(conn, amcheck_sql, opts.echo); + if (PQresultStatus(result) != PGRES_TUPLES_OK) + { + /* Querying the catalog failed. */ + pg_log_error("database \"%s\": %s", + PQdb(conn), PQerrorMessage(conn)); + pg_log_info("query was: %s", amcheck_sql); + PQclear(result); + disconnectDatabase(conn); + exit(1); + } + ntups = PQntuples(result); + if (ntups == 0) + { + /* Querying the catalog succeeded, but amcheck is missing. */ + pg_log_warning("skipping database \"%s\": amcheck is not installed", + PQdb(conn)); + disconnectDatabase(conn); + conn = NULL; + continue; + } + amcheck_schema = PQgetvalue(result, 0, 0); + if (opts.verbose) + pg_log_info("in database \"%s\": using amcheck version \"%s\" in schema \"%s\"", + PQdb(conn), PQgetvalue(result, 0, 1), amcheck_schema); + dat->amcheck_schema = PQescapeIdentifier(conn, amcheck_schema, + strlen(amcheck_schema)); + PQclear(result); + + compile_relation_list_one_db(conn, &relations, dat, &pagestotal); + } + + /* + * Check that all inclusion patterns matched at least one schema or + * relation that we can check. + */ + for (pattern_id = 0; pattern_id < opts.include.len; pattern_id++) + { + PatternInfo *pat = &opts.include.data[pattern_id]; + + if (!pat->matched && (pat->nsp_regex != NULL || pat->rel_regex != NULL)) + { + failed = opts.strict_names; + + if (pat->heap_only) + log_no_match("no heap tables to check matching \"%s\"", + pat->pattern); + else if (pat->btree_only) + log_no_match("no btree indexes to check matching \"%s\"", + pat->pattern); + else if (pat->rel_regex == NULL) + log_no_match("no relations to check in schemas matching \"%s\"", + pat->pattern); + else + log_no_match("no relations to check matching \"%s\"", + pat->pattern); + } + } + + if (failed) + { + if (conn != NULL) + disconnectDatabase(conn); + exit(1); + } + + /* + * Set parallel_workers to the lesser of opts.jobs and the number of + * relations. + */ + parallel_workers = 0; + for (cell = relations.head; cell; cell = cell->next) + { + reltotal++; + if (parallel_workers < opts.jobs) + parallel_workers++; + } + + if (reltotal == 0) + { + if (conn != NULL) + disconnectDatabase(conn); + pg_log_error("no relations to check"); + exit(1); + } + progress_report(reltotal, relprogress, pagestotal, pageschecked, + NULL, true, false); + + /* + * Main event loop. + * + * We use server-side parallelism to check up to parallel_workers + * relations in parallel. The list of relations was computed in database + * order, which minimizes the number of connects and disconnects as we + * process the list. + */ + latest_datname = NULL; + sa = ParallelSlotsSetup(parallel_workers, &cparams, progname, opts.echo, + NULL); + if (conn != NULL) + { + ParallelSlotsAdoptConn(sa, conn); + conn = NULL; + } + + initPQExpBuffer(&sql); + for (relprogress = 0, cell = relations.head; cell; cell = cell->next) + { + ParallelSlot *free_slot; + RelationInfo *rel; + + rel = (RelationInfo *) cell->ptr; + + if (CancelRequested) + { + failed = true; + break; + } + + /* + * The list of relations is in database sorted order. If this next + * relation is in a different database than the last one seen, we are + * about to start checking this database. Note that other slots may + * still be working on relations from prior databases. + */ + latest_datname = rel->datinfo->datname; + + progress_report(reltotal, relprogress, pagestotal, pageschecked, + latest_datname, false, false); + + relprogress++; + pageschecked += rel->blocks_to_check; + + /* + * Get a parallel slot for the next amcheck command, blocking if + * necessary until one is available, or until a previously issued slot + * command fails, indicating that we should abort checking the + * remaining objects. + */ + free_slot = ParallelSlotsGetIdle(sa, rel->datinfo->datname); + if (!free_slot) + { + /* + * Something failed. We don't need to know what it was, because + * the handler should already have emitted the necessary error + * messages. + */ + failed = true; + break; + } + + if (opts.verbose) + PQsetErrorVerbosity(free_slot->connection, PQERRORS_VERBOSE); + + /* + * Execute the appropriate amcheck command for this relation using our + * slot's database connection. We do not wait for the command to + * complete, nor do we perform any error checking, as that is done by + * the parallel slots and our handler callback functions. + */ + if (rel->is_heap) + { + if (opts.verbose) + { + if (opts.show_progress && progress_since_last_stderr) + fprintf(stderr, "\n"); + pg_log_info("checking heap table \"%s.%s.%s\"", + rel->datinfo->datname, rel->nspname, rel->relname); + progress_since_last_stderr = false; + } + prepare_heap_command(&sql, rel, free_slot->connection); + rel->sql = pstrdup(sql.data); /* pg_free'd after command */ + ParallelSlotSetHandler(free_slot, verify_heap_slot_handler, rel); + run_command(free_slot, rel->sql); + } + else + { + if (opts.verbose) + { + if (opts.show_progress && progress_since_last_stderr) + fprintf(stderr, "\n"); + + pg_log_info("checking btree index \"%s.%s.%s\"", + rel->datinfo->datname, rel->nspname, rel->relname); + progress_since_last_stderr = false; + } + prepare_btree_command(&sql, rel, free_slot->connection); + rel->sql = pstrdup(sql.data); /* pg_free'd after command */ + ParallelSlotSetHandler(free_slot, verify_btree_slot_handler, rel); + run_command(free_slot, rel->sql); + } + } + termPQExpBuffer(&sql); + + if (!failed) + { + + /* + * Wait for all slots to complete, or for one to indicate that an + * error occurred. Like above, we rely on the handler emitting the + * necessary error messages. + */ + if (sa && !ParallelSlotsWaitCompletion(sa)) + failed = true; + + progress_report(reltotal, relprogress, pagestotal, pageschecked, NULL, true, true); + } + + if (sa) + { + ParallelSlotsTerminate(sa); + FREE_AND_SET_NULL(sa); + } + + if (failed) + exit(1); + + if (!all_checks_pass) + exit(2); +} + +/* + * prepare_heap_command + * + * Creates a SQL command for running amcheck checking on the given heap + * relation. The command is phrased as a SQL query, with column order and + * names matching the expectations of verify_heap_slot_handler, which will + * receive and handle each row returned from the verify_heapam() function. + * + * The constructed SQL command will silently skip temporary tables, as checking + * them would needlessly draw errors from the underlying amcheck function. + * + * sql: buffer into which the heap table checking command will be written + * rel: relation information for the heap table to be checked + * conn: the connection to be used, for string escaping purposes + */ +static void +prepare_heap_command(PQExpBuffer sql, RelationInfo *rel, PGconn *conn) +{ + resetPQExpBuffer(sql); + appendPQExpBuffer(sql, + "SELECT v.blkno, v.offnum, v.attnum, v.msg " + "FROM pg_catalog.pg_class c, %s.verify_heapam(" + "\nrelation := c.oid, on_error_stop := %s, check_toast := %s, skip := '%s'", + rel->datinfo->amcheck_schema, + opts.on_error_stop ? "true" : "false", + opts.reconcile_toast ? "true" : "false", + opts.skip); + + if (opts.startblock >= 0) + appendPQExpBuffer(sql, ", startblock := " INT64_FORMAT, opts.startblock); + if (opts.endblock >= 0) + appendPQExpBuffer(sql, ", endblock := " INT64_FORMAT, opts.endblock); + + appendPQExpBuffer(sql, + "\n) v WHERE c.oid = %u " + "AND c.relpersistence != 't'", + rel->reloid); +} + +/* + * prepare_btree_command + * + * Creates a SQL command for running amcheck checking on the given btree index + * relation. The command does not select any columns, as btree checking + * functions do not return any, but rather return corruption information by + * raising errors, which verify_btree_slot_handler expects. + * + * The constructed SQL command will silently skip temporary indexes, and + * indexes being reindexed concurrently, as checking them would needlessly draw + * errors from the underlying amcheck functions. + * + * sql: buffer into which the heap table checking command will be written + * rel: relation information for the index to be checked + * conn: the connection to be used, for string escaping purposes + */ +static void +prepare_btree_command(PQExpBuffer sql, RelationInfo *rel, PGconn *conn) +{ + resetPQExpBuffer(sql); + + if (opts.parent_check) + appendPQExpBuffer(sql, + "SELECT %s.bt_index_parent_check(" + "index := c.oid, heapallindexed := %s, rootdescend := %s)" + "\nFROM pg_catalog.pg_class c, pg_catalog.pg_index i " + "WHERE c.oid = %u " + "AND c.oid = i.indexrelid " + "AND c.relpersistence != 't' " + "AND i.indisready AND i.indisvalid AND i.indislive", + rel->datinfo->amcheck_schema, + (opts.heapallindexed ? "true" : "false"), + (opts.rootdescend ? "true" : "false"), + rel->reloid); + else + appendPQExpBuffer(sql, + "SELECT %s.bt_index_check(" + "index := c.oid, heapallindexed := %s)" + "\nFROM pg_catalog.pg_class c, pg_catalog.pg_index i " + "WHERE c.oid = %u " + "AND c.oid = i.indexrelid " + "AND c.relpersistence != 't' " + "AND i.indisready AND i.indisvalid AND i.indislive", + rel->datinfo->amcheck_schema, + (opts.heapallindexed ? "true" : "false"), + rel->reloid); +} + +/* + * run_command + * + * Sends a command to the server without waiting for the command to complete. + * Logs an error if the command cannot be sent, but otherwise any errors are + * expected to be handled by a ParallelSlotHandler. + * + * If reconnecting to the database is necessary, the cparams argument may be + * modified. + * + * slot: slot with connection to the server we should use for the command + * sql: query to send + */ +static void +run_command(ParallelSlot *slot, const char *sql) +{ + if (opts.echo) + printf("%s\n", sql); + + if (PQsendQuery(slot->connection, sql) == 0) + { + pg_log_error("error sending command to database \"%s\": %s", + PQdb(slot->connection), + PQerrorMessage(slot->connection)); + pg_log_error("command was: %s", sql); + exit(1); + } +} + +/* + * should_processing_continue + * + * Checks a query result returned from a query (presumably issued on a slot's + * connection) to determine if parallel slots should continue issuing further + * commands. + * + * Note: Heap relation corruption is reported by verify_heapam() via the result + * set, rather than an ERROR, but running verify_heapam() on a corrupted heap + * table may still result in an error being returned from the server due to + * missing relation files, bad checksums, etc. The btree corruption checking + * functions always use errors to communicate corruption messages. We can't + * just abort processing because we got a mere ERROR. + * + * res: result from an executed sql query + */ +static bool +should_processing_continue(PGresult *res) +{ + const char *severity; + + switch (PQresultStatus(res)) + { + /* These are expected and ok */ + case PGRES_COMMAND_OK: + case PGRES_TUPLES_OK: + case PGRES_NONFATAL_ERROR: + break; + + /* This is expected but requires closer scrutiny */ + case PGRES_FATAL_ERROR: + severity = PQresultErrorField(res, PG_DIAG_SEVERITY_NONLOCALIZED); + if (severity == NULL) + return false; /* libpq failure, probably lost connection */ + if (strcmp(severity, "FATAL") == 0) + return false; + if (strcmp(severity, "PANIC") == 0) + return false; + break; + + /* These are unexpected */ + case PGRES_BAD_RESPONSE: + case PGRES_EMPTY_QUERY: + case PGRES_COPY_OUT: + case PGRES_COPY_IN: + case PGRES_COPY_BOTH: + case PGRES_SINGLE_TUPLE: + case PGRES_PIPELINE_SYNC: + case PGRES_PIPELINE_ABORTED: + return false; + } + return true; +} + +/* + * Returns a copy of the argument string with all lines indented four spaces. + * + * The caller should pg_free the result when finished with it. + */ +static char * +indent_lines(const char *str) +{ + PQExpBufferData buf; + const char *c; + char *result; + + initPQExpBuffer(&buf); + appendPQExpBufferStr(&buf, " "); + for (c = str; *c; c++) + { + appendPQExpBufferChar(&buf, *c); + if (c[0] == '\n' && c[1] != '\0') + appendPQExpBufferStr(&buf, " "); + } + result = pstrdup(buf.data); + termPQExpBuffer(&buf); + + return result; +} + +/* + * verify_heap_slot_handler + * + * ParallelSlotHandler that receives results from a heap table checking command + * created by prepare_heap_command and outputs the results for the user. + * + * res: result from an executed sql query + * conn: connection on which the sql query was executed + * context: the sql query being handled, as a cstring + */ +static bool +verify_heap_slot_handler(PGresult *res, PGconn *conn, void *context) +{ + RelationInfo *rel = (RelationInfo *) context; + + if (PQresultStatus(res) == PGRES_TUPLES_OK) + { + int i; + int ntups = PQntuples(res); + + if (ntups > 0) + all_checks_pass = false; + + for (i = 0; i < ntups; i++) + { + const char *msg; + + /* The message string should never be null, but check */ + if (PQgetisnull(res, i, 3)) + msg = "NO MESSAGE"; + else + msg = PQgetvalue(res, i, 3); + + if (!PQgetisnull(res, i, 2)) + printf(_("heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n"), + rel->datinfo->datname, rel->nspname, rel->relname, + PQgetvalue(res, i, 0), /* blkno */ + PQgetvalue(res, i, 1), /* offnum */ + PQgetvalue(res, i, 2)); /* attnum */ + + else if (!PQgetisnull(res, i, 1)) + printf(_("heap table \"%s.%s.%s\", block %s, offset %s:\n"), + rel->datinfo->datname, rel->nspname, rel->relname, + PQgetvalue(res, i, 0), /* blkno */ + PQgetvalue(res, i, 1)); /* offnum */ + + else if (!PQgetisnull(res, i, 0)) + printf(_("heap table \"%s.%s.%s\", block %s:\n"), + rel->datinfo->datname, rel->nspname, rel->relname, + PQgetvalue(res, i, 0)); /* blkno */ + + else + printf(_("heap table \"%s.%s.%s\":\n"), + rel->datinfo->datname, rel->nspname, rel->relname); + + printf(" %s\n", msg); + } + } + else if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + char *msg = indent_lines(PQerrorMessage(conn)); + + all_checks_pass = false; + printf(_("heap table \"%s.%s.%s\":\n"), + rel->datinfo->datname, rel->nspname, rel->relname); + printf("%s", msg); + if (opts.verbose) + printf(_("query was: %s\n"), rel->sql); + FREE_AND_SET_NULL(msg); + } + + FREE_AND_SET_NULL(rel->sql); + FREE_AND_SET_NULL(rel->nspname); + FREE_AND_SET_NULL(rel->relname); + + return should_processing_continue(res); +} + +/* + * verify_btree_slot_handler + * + * ParallelSlotHandler that receives results from a btree checking command + * created by prepare_btree_command and outputs them for the user. The results + * from the btree checking command is assumed to be empty, but when the results + * are an error code, the useful information about the corruption is expected + * in the connection's error message. + * + * res: result from an executed sql query + * conn: connection on which the sql query was executed + * context: unused + */ +static bool +verify_btree_slot_handler(PGresult *res, PGconn *conn, void *context) +{ + RelationInfo *rel = (RelationInfo *) context; + + if (PQresultStatus(res) == PGRES_TUPLES_OK) + { + int ntups = PQntuples(res); + + if (ntups > 1) + { + /* + * We expect the btree checking functions to return one void row + * each, or zero rows if the check was skipped due to the object + * being in the wrong state to be checked, so we should output some + * sort of warning if we get anything more, not because it + * indicates corruption, but because it suggests a mismatch between + * amcheck and pg_amcheck versions. + * + * In conjunction with --progress, anything written to stderr at + * this time would present strangely to the user without an extra + * newline, so we print one. If we were multithreaded, we'd have + * to avoid splitting this across multiple calls, but we're in an + * event loop, so it doesn't matter. + */ + if (opts.show_progress && progress_since_last_stderr) + fprintf(stderr, "\n"); + pg_log_warning("btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d", + rel->datinfo->datname, rel->nspname, rel->relname, ntups); + if (opts.verbose) + pg_log_info("query was: %s", rel->sql); + pg_log_warning("Are %s's and amcheck's versions compatible?", + progname); + progress_since_last_stderr = false; + } + } + else + { + char *msg = indent_lines(PQerrorMessage(conn)); + + all_checks_pass = false; + printf(_("btree index \"%s.%s.%s\":\n"), + rel->datinfo->datname, rel->nspname, rel->relname); + printf("%s", msg); + if (opts.verbose) + printf(_("query was: %s\n"), rel->sql); + FREE_AND_SET_NULL(msg); + } + + FREE_AND_SET_NULL(rel->sql); + FREE_AND_SET_NULL(rel->nspname); + FREE_AND_SET_NULL(rel->relname); + + return should_processing_continue(res); +} + +/* + * help + * + * Prints help page for the program + * + * progname: the name of the executed program, such as "pg_amcheck" + */ +static void +help(const char *progname) +{ + printf(_("%s checks objects in a PostgreSQL database for corruption.\n\n"), progname); + printf(_("Usage:\n")); + printf(_(" %s [OPTION]... [DBNAME]\n"), progname); + printf(_("\nTarget options:\n")); + printf(_(" -a, --all check all databases\n")); + printf(_(" -d, --database=PATTERN check matching database(s)\n")); + printf(_(" -D, --exclude-database=PATTERN do NOT check matching database(s)\n")); + printf(_(" -i, --index=PATTERN check matching index(es)\n")); + printf(_(" -I, --exclude-index=PATTERN do NOT check matching index(es)\n")); + printf(_(" -r, --relation=PATTERN check matching relation(s)\n")); + printf(_(" -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n")); + printf(_(" -s, --schema=PATTERN check matching schema(s)\n")); + printf(_(" -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n")); + printf(_(" -t, --table=PATTERN check matching table(s)\n")); + printf(_(" -T, --exclude-table=PATTERN do NOT check matching table(s)\n")); + printf(_(" --no-dependent-indexes do NOT expand list of relations to include indexes\n")); + printf(_(" --no-dependent-toast do NOT expand list of relations to include TOAST tables\n")); + printf(_(" --no-strict-names do NOT require patterns to match objects\n")); + printf(_("\nTable checking options:\n")); + printf(_(" --exclude-toast-pointers do NOT follow relation TOAST pointers\n")); + printf(_(" --on-error-stop stop checking at end of first corrupt page\n")); + printf(_(" --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n")); + printf(_(" --startblock=BLOCK begin checking table(s) at the given block number\n")); + printf(_(" --endblock=BLOCK check table(s) only up to the given block number\n")); + printf(_("\nB-tree index checking options:\n")); + printf(_(" --heapallindexed check that all heap tuples are found within indexes\n")); + printf(_(" --parent-check check index parent/child relationships\n")); + printf(_(" --rootdescend search from root page to refind tuples\n")); + printf(_("\nConnection options:\n")); + printf(_(" -h, --host=HOSTNAME database server host or socket directory\n")); + printf(_(" -p, --port=PORT database server port\n")); + printf(_(" -U, --username=USERNAME user name to connect as\n")); + printf(_(" -w, --no-password never prompt for password\n")); + printf(_(" -W, --password force password prompt\n")); + printf(_(" --maintenance-db=DBNAME alternate maintenance database\n")); + printf(_("\nOther options:\n")); + printf(_(" -e, --echo show the commands being sent to the server\n")); + printf(_(" -j, --jobs=NUM use this many concurrent connections to the server\n")); + printf(_(" -P, --progress show progress information\n")); + printf(_(" -v, --verbose write a lot of output\n")); + printf(_(" -V, --version output version information, then exit\n")); + printf(_(" --install-missing install missing extensions\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); +} + +/* + * Print a progress report based on the global variables. + * + * Progress report is written at maximum once per second, unless the force + * parameter is set to true. + * + * If finished is set to true, this is the last progress report. The cursor + * is moved to the next line. + */ +static void +progress_report(uint64 relations_total, uint64 relations_checked, + uint64 relpages_total, uint64 relpages_checked, + const char *datname, bool force, bool finished) +{ + int percent_rel = 0; + int percent_pages = 0; + char checked_rel[32]; + char total_rel[32]; + char checked_pages[32]; + char total_pages[32]; + pg_time_t now; + + if (!opts.show_progress) + return; + + now = time(NULL); + if (now == last_progress_report && !force && !finished) + return; /* Max once per second */ + + last_progress_report = now; + if (relations_total) + percent_rel = (int) (relations_checked * 100 / relations_total); + if (relpages_total) + percent_pages = (int) (relpages_checked * 100 / relpages_total); + + /* + * Separate step to keep platform-dependent format code out of fprintf + * calls. We only test for INT64_FORMAT availability in snprintf, not + * fprintf. + */ + snprintf(checked_rel, sizeof(checked_rel), INT64_FORMAT, relations_checked); + snprintf(total_rel, sizeof(total_rel), INT64_FORMAT, relations_total); + snprintf(checked_pages, sizeof(checked_pages), INT64_FORMAT, relpages_checked); + snprintf(total_pages, sizeof(total_pages), INT64_FORMAT, relpages_total); + +#define VERBOSE_DATNAME_LENGTH 35 + if (opts.verbose) + { + if (!datname) + + /* + * No datname given, so clear the status line (used for first and + * last call) + */ + fprintf(stderr, + _("%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s"), + (int) strlen(total_rel), + checked_rel, total_rel, percent_rel, + (int) strlen(total_pages), + checked_pages, total_pages, percent_pages, + VERBOSE_DATNAME_LENGTH + 2, ""); + else + { + bool truncate = (strlen(datname) > VERBOSE_DATNAME_LENGTH); + + fprintf(stderr, + _("%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)"), + (int) strlen(total_rel), + checked_rel, total_rel, percent_rel, + (int) strlen(total_pages), + checked_pages, total_pages, percent_pages, + /* Prefix with "..." if we do leading truncation */ + truncate ? "..." : "", + truncate ? VERBOSE_DATNAME_LENGTH - 3 : VERBOSE_DATNAME_LENGTH, + truncate ? VERBOSE_DATNAME_LENGTH - 3 : VERBOSE_DATNAME_LENGTH, + /* Truncate datname at beginning if it's too long */ + truncate ? datname + strlen(datname) - VERBOSE_DATNAME_LENGTH + 3 : datname); + } + } + else + fprintf(stderr, + _("%*s/%s relations (%d%%), %*s/%s pages (%d%%)"), + (int) strlen(total_rel), + checked_rel, total_rel, percent_rel, + (int) strlen(total_pages), + checked_pages, total_pages, percent_pages); + + /* + * Stay on the same line if reporting to a terminal and we're not done + * yet. + */ + if (!finished && isatty(fileno(stderr))) + { + fputc('\r', stderr); + progress_since_last_stderr = true; + } + else + fputc('\n', stderr); +} + +/* + * Extend the pattern info array to hold one additional initialized pattern + * info entry. + * + * Returns a pointer to the new entry. + */ +static PatternInfo * +extend_pattern_info_array(PatternInfoArray *pia) +{ + PatternInfo *result; + + pia->len++; + pia->data = (PatternInfo *) pg_realloc(pia->data, pia->len * sizeof(PatternInfo)); + result = &pia->data[pia->len - 1]; + memset(result, 0, sizeof(*result)); + + return result; +} + +/* + * append_database_pattern + * + * Adds the given pattern interpreted as a database name pattern. + * + * pia: the pattern info array to be appended + * pattern: the database name pattern + * encoding: client encoding for parsing the pattern + */ +static void +append_database_pattern(PatternInfoArray *pia, const char *pattern, int encoding) +{ + PQExpBufferData buf; + int dotcnt; + PatternInfo *info = extend_pattern_info_array(pia); + + initPQExpBuffer(&buf); + patternToSQLRegex(encoding, NULL, NULL, &buf, pattern, false, false, + &dotcnt); + if (dotcnt > 0) + { + pg_log_error("improper qualified name (too many dotted names): %s", pattern); + exit(2); + } + info->pattern = pattern; + info->db_regex = pstrdup(buf.data); + + termPQExpBuffer(&buf); +} + +/* + * append_schema_pattern + * + * Adds the given pattern interpreted as a schema name pattern. + * + * pia: the pattern info array to be appended + * pattern: the schema name pattern + * encoding: client encoding for parsing the pattern + */ +static void +append_schema_pattern(PatternInfoArray *pia, const char *pattern, int encoding) +{ + PQExpBufferData dbbuf; + PQExpBufferData nspbuf; + int dotcnt; + PatternInfo *info = extend_pattern_info_array(pia); + + initPQExpBuffer(&dbbuf); + initPQExpBuffer(&nspbuf); + + patternToSQLRegex(encoding, NULL, &dbbuf, &nspbuf, pattern, false, false, + &dotcnt); + if (dotcnt > 1) + { + pg_log_error("improper qualified name (too many dotted names): %s", pattern); + exit(2); + } + info->pattern = pattern; + if (dbbuf.data[0]) + { + opts.dbpattern = true; + info->db_regex = pstrdup(dbbuf.data); + } + if (nspbuf.data[0]) + info->nsp_regex = pstrdup(nspbuf.data); + + termPQExpBuffer(&dbbuf); + termPQExpBuffer(&nspbuf); +} + +/* + * append_relation_pattern_helper + * + * Adds to a list the given pattern interpreted as a relation pattern. + * + * pia: the pattern info array to be appended + * pattern: the relation name pattern + * encoding: client encoding for parsing the pattern + * heap_only: whether the pattern should only be matched against heap tables + * btree_only: whether the pattern should only be matched against btree indexes + */ +static void +append_relation_pattern_helper(PatternInfoArray *pia, const char *pattern, + int encoding, bool heap_only, bool btree_only) +{ + PQExpBufferData dbbuf; + PQExpBufferData nspbuf; + PQExpBufferData relbuf; + int dotcnt; + PatternInfo *info = extend_pattern_info_array(pia); + + initPQExpBuffer(&dbbuf); + initPQExpBuffer(&nspbuf); + initPQExpBuffer(&relbuf); + + patternToSQLRegex(encoding, &dbbuf, &nspbuf, &relbuf, pattern, false, + false, &dotcnt); + if (dotcnt > 2) + { + pg_log_error("improper relation name (too many dotted names): %s", pattern); + exit(2); + } + info->pattern = pattern; + if (dbbuf.data[0]) + { + opts.dbpattern = true; + info->db_regex = pstrdup(dbbuf.data); + } + if (nspbuf.data[0]) + info->nsp_regex = pstrdup(nspbuf.data); + if (relbuf.data[0]) + info->rel_regex = pstrdup(relbuf.data); + + termPQExpBuffer(&dbbuf); + termPQExpBuffer(&nspbuf); + termPQExpBuffer(&relbuf); + + info->heap_only = heap_only; + info->btree_only = btree_only; +} + +/* + * append_relation_pattern + * + * Adds the given pattern interpreted as a relation pattern, to be matched + * against both heap tables and btree indexes. + * + * pia: the pattern info array to be appended + * pattern: the relation name pattern + * encoding: client encoding for parsing the pattern + */ +static void +append_relation_pattern(PatternInfoArray *pia, const char *pattern, int encoding) +{ + append_relation_pattern_helper(pia, pattern, encoding, false, false); +} + +/* + * append_heap_pattern + * + * Adds the given pattern interpreted as a relation pattern, to be matched only + * against heap tables. + * + * pia: the pattern info array to be appended + * pattern: the relation name pattern + * encoding: client encoding for parsing the pattern + */ +static void +append_heap_pattern(PatternInfoArray *pia, const char *pattern, int encoding) +{ + append_relation_pattern_helper(pia, pattern, encoding, true, false); +} + +/* + * append_btree_pattern + * + * Adds the given pattern interpreted as a relation pattern, to be matched only + * against btree indexes. + * + * pia: the pattern info array to be appended + * pattern: the relation name pattern + * encoding: client encoding for parsing the pattern + */ +static void +append_btree_pattern(PatternInfoArray *pia, const char *pattern, int encoding) +{ + append_relation_pattern_helper(pia, pattern, encoding, false, true); +} + +/* + * append_db_pattern_cte + * + * Appends to the buffer the body of a Common Table Expression (CTE) containing + * the database portions filtered from the list of patterns expressed as two + * columns: + * + * pattern_id: the index of this pattern in pia->data[] + * rgx: the database regular expression parsed from the pattern + * + * Patterns without a database portion are skipped. Patterns with more than + * just a database portion are optionally skipped, depending on argument + * 'inclusive'. + * + * buf: the buffer to be appended + * pia: the array of patterns to be inserted into the CTE + * conn: the database connection + * inclusive: whether to include patterns with schema and/or relation parts + * + * Returns whether any database patterns were appended. + */ +static bool +append_db_pattern_cte(PQExpBuffer buf, const PatternInfoArray *pia, + PGconn *conn, bool inclusive) +{ + int pattern_id; + const char *comma; + bool have_values; + + comma = ""; + have_values = false; + for (pattern_id = 0; pattern_id < pia->len; pattern_id++) + { + PatternInfo *info = &pia->data[pattern_id]; + + if (info->db_regex != NULL && + (inclusive || (info->nsp_regex == NULL && info->rel_regex == NULL))) + { + if (!have_values) + appendPQExpBufferStr(buf, "\nVALUES"); + have_values = true; + appendPQExpBuffer(buf, "%s\n(%d, ", comma, pattern_id); + appendStringLiteralConn(buf, info->db_regex, conn); + appendPQExpBufferStr(buf, ")"); + comma = ","; + } + } + + if (!have_values) + appendPQExpBufferStr(buf, "\nSELECT NULL, NULL, NULL WHERE false"); + + return have_values; +} + +/* + * compile_database_list + * + * If any database patterns exist, or if --all was given, compiles a distinct + * list of databases to check using a SQL query based on the patterns plus the + * literal initial database name, if given. If no database patterns exist and + * --all was not given, the query is not necessary, and only the initial + * database name (if any) is added to the list. + * + * conn: connection to the initial database + * databases: the list onto which databases should be appended + * initial_dbname: an optional extra database name to include in the list + */ +static void +compile_database_list(PGconn *conn, SimplePtrList *databases, + const char *initial_dbname) +{ + PGresult *res; + PQExpBufferData sql; + int ntups; + int i; + bool fatal; + + if (initial_dbname) + { + DatabaseInfo *dat = (DatabaseInfo *) pg_malloc0(sizeof(DatabaseInfo)); + + /* This database is included. Add to list */ + if (opts.verbose) + pg_log_info("including database \"%s\"", initial_dbname); + + dat->datname = pstrdup(initial_dbname); + simple_ptr_list_append(databases, dat); + } + + initPQExpBuffer(&sql); + + /* Append the include patterns CTE. */ + appendPQExpBufferStr(&sql, "WITH include_raw (pattern_id, rgx) AS ("); + if (!append_db_pattern_cte(&sql, &opts.include, conn, true) && + !opts.alldb) + { + /* + * None of the inclusion patterns (if any) contain database portions, + * so there is no need to query the database to resolve database + * patterns. + * + * Since we're also not operating under --all, we don't need to query + * the exhaustive list of connectable databases, either. + */ + termPQExpBuffer(&sql); + return; + } + + /* Append the exclude patterns CTE. */ + appendPQExpBufferStr(&sql, "),\nexclude_raw (pattern_id, rgx) AS ("); + append_db_pattern_cte(&sql, &opts.exclude, conn, false); + appendPQExpBufferStr(&sql, "),"); + + /* + * Append the database CTE, which includes whether each database is + * connectable and also joins against exclude_raw to determine whether + * each database is excluded. + */ + appendPQExpBufferStr(&sql, + "\ndatabase (datname) AS (" + "\nSELECT d.datname " + "FROM pg_catalog.pg_database d " + "LEFT OUTER JOIN exclude_raw e " + "ON d.datname ~ e.rgx " + "\nWHERE d.datallowconn " + "AND e.pattern_id IS NULL" + ")," + + /* + * Append the include_pat CTE, which joins the include_raw CTE against the + * databases CTE to determine if all the inclusion patterns had matches, + * and whether each matched pattern had the misfortune of only matching + * excluded or unconnectable databases. + */ + "\ninclude_pat (pattern_id, checkable) AS (" + "\nSELECT i.pattern_id, " + "COUNT(*) FILTER (" + "WHERE d IS NOT NULL" + ") AS checkable" + "\nFROM include_raw i " + "LEFT OUTER JOIN database d " + "ON d.datname ~ i.rgx" + "\nGROUP BY i.pattern_id" + ")," + + /* + * Append the filtered_databases CTE, which selects from the database CTE + * optionally joined against the include_raw CTE to only select databases + * that match an inclusion pattern. This appears to duplicate what the + * include_pat CTE already did above, but here we want only databases, and + * there we wanted patterns. + */ + "\nfiltered_databases (datname) AS (" + "\nSELECT DISTINCT d.datname " + "FROM database d"); + if (!opts.alldb) + appendPQExpBufferStr(&sql, + " INNER JOIN include_raw i " + "ON d.datname ~ i.rgx"); + appendPQExpBufferStr(&sql, + ")" + + /* + * Select the checkable databases and the unmatched inclusion patterns. + */ + "\nSELECT pattern_id, datname FROM (" + "\nSELECT pattern_id, NULL::TEXT AS datname " + "FROM include_pat " + "WHERE checkable = 0 " + "UNION ALL" + "\nSELECT NULL, datname " + "FROM filtered_databases" + ") AS combined_records" + "\nORDER BY pattern_id NULLS LAST, datname"); + + res = executeQuery(conn, sql.data, opts.echo); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + pg_log_error("query failed: %s", PQerrorMessage(conn)); + pg_log_info("query was: %s", sql.data); + disconnectDatabase(conn); + exit(1); + } + termPQExpBuffer(&sql); + + ntups = PQntuples(res); + for (fatal = false, i = 0; i < ntups; i++) + { + int pattern_id = -1; + const char *datname = NULL; + + if (!PQgetisnull(res, i, 0)) + pattern_id = atoi(PQgetvalue(res, i, 0)); + if (!PQgetisnull(res, i, 1)) + datname = PQgetvalue(res, i, 1); + + if (pattern_id >= 0) + { + /* + * Current record pertains to an inclusion pattern that matched no + * checkable databases. + */ + fatal = opts.strict_names; + if (pattern_id >= opts.include.len) + { + pg_log_error("internal error: received unexpected database pattern_id %d", + pattern_id); + exit(1); + } + log_no_match("no connectable databases to check matching \"%s\"", + opts.include.data[pattern_id].pattern); + } + else + { + DatabaseInfo *dat; + + /* Current record pertains to a database */ + Assert(datname != NULL); + + /* Avoid entering a duplicate entry matching the initial_dbname */ + if (initial_dbname != NULL && strcmp(initial_dbname, datname) == 0) + continue; + + /* This database is included. Add to list */ + if (opts.verbose) + pg_log_info("including database \"%s\"", datname); + + dat = (DatabaseInfo *) pg_malloc0(sizeof(DatabaseInfo)); + dat->datname = pstrdup(datname); + simple_ptr_list_append(databases, dat); + } + } + PQclear(res); + + if (fatal) + { + if (conn != NULL) + disconnectDatabase(conn); + exit(1); + } +} + +/* + * append_rel_pattern_raw_cte + * + * Appends to the buffer the body of a Common Table Expression (CTE) containing + * the given patterns as six columns: + * + * pattern_id: the index of this pattern in pia->data[] + * db_regex: the database regexp parsed from the pattern, or NULL if the + * pattern had no database part + * nsp_regex: the namespace regexp parsed from the pattern, or NULL if the + * pattern had no namespace part + * rel_regex: the relname regexp parsed from the pattern, or NULL if the + * pattern had no relname part + * heap_only: true if the pattern applies only to heap tables (not indexes) + * btree_only: true if the pattern applies only to btree indexes (not tables) + * + * buf: the buffer to be appended + * patterns: the array of patterns to be inserted into the CTE + * conn: the database connection + */ +static void +append_rel_pattern_raw_cte(PQExpBuffer buf, const PatternInfoArray *pia, + PGconn *conn) +{ + int pattern_id; + const char *comma; + bool have_values; + + comma = ""; + have_values = false; + for (pattern_id = 0; pattern_id < pia->len; pattern_id++) + { + PatternInfo *info = &pia->data[pattern_id]; + + if (!have_values) + appendPQExpBufferStr(buf, "\nVALUES"); + have_values = true; + appendPQExpBuffer(buf, "%s\n(%d::INTEGER, ", comma, pattern_id); + if (info->db_regex == NULL) + appendPQExpBufferStr(buf, "NULL"); + else + appendStringLiteralConn(buf, info->db_regex, conn); + appendPQExpBufferStr(buf, "::TEXT, "); + if (info->nsp_regex == NULL) + appendPQExpBufferStr(buf, "NULL"); + else + appendStringLiteralConn(buf, info->nsp_regex, conn); + appendPQExpBufferStr(buf, "::TEXT, "); + if (info->rel_regex == NULL) + appendPQExpBufferStr(buf, "NULL"); + else + appendStringLiteralConn(buf, info->rel_regex, conn); + if (info->heap_only) + appendPQExpBufferStr(buf, "::TEXT, true::BOOLEAN"); + else + appendPQExpBufferStr(buf, "::TEXT, false::BOOLEAN"); + if (info->btree_only) + appendPQExpBufferStr(buf, ", true::BOOLEAN"); + else + appendPQExpBufferStr(buf, ", false::BOOLEAN"); + appendPQExpBufferStr(buf, ")"); + comma = ","; + } + + if (!have_values) + appendPQExpBufferStr(buf, + "\nSELECT NULL::INTEGER, NULL::TEXT, NULL::TEXT, " + "NULL::TEXT, NULL::BOOLEAN, NULL::BOOLEAN " + "WHERE false"); +} + +/* + * append_rel_pattern_filtered_cte + * + * Appends to the buffer a Common Table Expression (CTE) which selects + * all patterns from the named raw CTE, filtered by database. All patterns + * which have no database portion or whose database portion matches our + * connection's database name are selected, with other patterns excluded. + * + * The basic idea here is that if we're connected to database "foo" and we have + * patterns "foo.bar.baz", "alpha.beta" and "one.two.three", we only want to + * use the first two while processing relations in this database, as the third + * one is not relevant. + * + * buf: the buffer to be appended + * raw: the name of the CTE to select from + * filtered: the name of the CTE to create + * conn: the database connection + */ +static void +append_rel_pattern_filtered_cte(PQExpBuffer buf, const char *raw, + const char *filtered, PGconn *conn) +{ + appendPQExpBuffer(buf, + "\n%s (pattern_id, nsp_regex, rel_regex, heap_only, btree_only) AS (" + "\nSELECT pattern_id, nsp_regex, rel_regex, heap_only, btree_only " + "FROM %s r" + "\nWHERE (r.db_regex IS NULL " + "OR ", + filtered, raw); + appendStringLiteralConn(buf, PQdb(conn), conn); + appendPQExpBufferStr(buf, " ~ r.db_regex)"); + appendPQExpBufferStr(buf, + " AND (r.nsp_regex IS NOT NULL" + " OR r.rel_regex IS NOT NULL)" + "),"); +} + +/* + * compile_relation_list_one_db + * + * Compiles a list of relations to check within the currently connected + * database based on the user supplied options, sorted by descending size, + * and appends them to the given list of relations. + * + * The cells of the constructed list contain all information about the relation + * necessary to connect to the database and check the object, including which + * database to connect to, where contrib/amcheck is installed, and the Oid and + * type of object (heap table vs. btree index). Rather than duplicating the + * database details per relation, the relation structs use references to the + * same database object, provided by the caller. + * + * conn: connection to this next database, which should be the same as in 'dat' + * relations: list onto which the relations information should be appended + * dat: the database info struct for use by each relation + * pagecount: gets incremented by the number of blocks to check in all + * relations added + */ +static void +compile_relation_list_one_db(PGconn *conn, SimplePtrList *relations, + const DatabaseInfo *dat, + uint64 *pagecount) +{ + PGresult *res; + PQExpBufferData sql; + int ntups; + int i; + + initPQExpBuffer(&sql); + appendPQExpBufferStr(&sql, "WITH"); + + /* Append CTEs for the relation inclusion patterns, if any */ + if (!opts.allrel) + { + appendPQExpBufferStr(&sql, + " include_raw (pattern_id, db_regex, nsp_regex, rel_regex, heap_only, btree_only) AS ("); + append_rel_pattern_raw_cte(&sql, &opts.include, conn); + appendPQExpBufferStr(&sql, "\n),"); + append_rel_pattern_filtered_cte(&sql, "include_raw", "include_pat", conn); + } + + /* Append CTEs for the relation exclusion patterns, if any */ + if (opts.excludetbl || opts.excludeidx || opts.excludensp) + { + appendPQExpBufferStr(&sql, + " exclude_raw (pattern_id, db_regex, nsp_regex, rel_regex, heap_only, btree_only) AS ("); + append_rel_pattern_raw_cte(&sql, &opts.exclude, conn); + appendPQExpBufferStr(&sql, "\n),"); + append_rel_pattern_filtered_cte(&sql, "exclude_raw", "exclude_pat", conn); + } + + /* Append the relation CTE. */ + appendPQExpBufferStr(&sql, + " relation (pattern_id, oid, nspname, relname, reltoastrelid, relpages, is_heap, is_btree) AS (" + "\nSELECT DISTINCT ON (c.oid"); + if (!opts.allrel) + appendPQExpBufferStr(&sql, ", ip.pattern_id) ip.pattern_id,"); + else + appendPQExpBufferStr(&sql, ") NULL::INTEGER AS pattern_id,"); + appendPQExpBuffer(&sql, + "\nc.oid, n.nspname, c.relname, c.reltoastrelid, c.relpages, " + "c.relam = %u AS is_heap, " + "c.relam = %u AS is_btree" + "\nFROM pg_catalog.pg_class c " + "INNER JOIN pg_catalog.pg_namespace n " + "ON c.relnamespace = n.oid", + HEAP_TABLE_AM_OID, BTREE_AM_OID); + if (!opts.allrel) + appendPQExpBuffer(&sql, + "\nINNER JOIN include_pat ip" + "\nON (n.nspname ~ ip.nsp_regex OR ip.nsp_regex IS NULL)" + "\nAND (c.relname ~ ip.rel_regex OR ip.rel_regex IS NULL)" + "\nAND (c.relam = %u OR NOT ip.heap_only)" + "\nAND (c.relam = %u OR NOT ip.btree_only)", + HEAP_TABLE_AM_OID, BTREE_AM_OID); + if (opts.excludetbl || opts.excludeidx || opts.excludensp) + appendPQExpBuffer(&sql, + "\nLEFT OUTER JOIN exclude_pat ep" + "\nON (n.nspname ~ ep.nsp_regex OR ep.nsp_regex IS NULL)" + "\nAND (c.relname ~ ep.rel_regex OR ep.rel_regex IS NULL)" + "\nAND (c.relam = %u OR NOT ep.heap_only OR ep.rel_regex IS NULL)" + "\nAND (c.relam = %u OR NOT ep.btree_only OR ep.rel_regex IS NULL)", + HEAP_TABLE_AM_OID, BTREE_AM_OID); + + /* + * Exclude temporary tables and indexes, which must necessarily belong to + * other sessions. (We don't create any ourselves.) We must ultimately + * exclude indexes marked invalid or not ready, but we delay that decision + * until firing off the amcheck command, as the state of an index may + * change by then. + */ + appendPQExpBufferStr(&sql, "\nWHERE c.relpersistence != 't'"); + if (opts.excludetbl || opts.excludeidx || opts.excludensp) + appendPQExpBufferStr(&sql, "\nAND ep.pattern_id IS NULL"); + + /* + * We need to be careful not to break the --no-dependent-toast and + * --no-dependent-indexes options. By default, the btree indexes, toast + * tables, and toast table btree indexes associated with primary heap + * tables are included, using their own CTEs below. We implement the + * --exclude-* options by not creating those CTEs, but that's no use if + * we've already selected the toast and indexes here. On the other hand, + * we want inclusion patterns that match indexes or toast tables to be + * honored. So, if inclusion patterns were given, we want to select all + * tables, toast tables, or indexes that match the patterns. But if no + * inclusion patterns were given, and we're simply matching all relations, + * then we only want to match the primary tables here. + */ + if (opts.allrel) + appendPQExpBuffer(&sql, + " AND c.relam = %u " + "AND c.relkind IN ('r', 'm', 't') " + "AND c.relnamespace != %u", + HEAP_TABLE_AM_OID, PG_TOAST_NAMESPACE); + else + appendPQExpBuffer(&sql, + " AND c.relam IN (%u, %u)" + "AND c.relkind IN ('r', 'm', 't', 'i') " + "AND ((c.relam = %u AND c.relkind IN ('r', 'm', 't')) OR " + "(c.relam = %u AND c.relkind = 'i'))", + HEAP_TABLE_AM_OID, BTREE_AM_OID, + HEAP_TABLE_AM_OID, BTREE_AM_OID); + + appendPQExpBufferStr(&sql, + "\nORDER BY c.oid)"); + + if (!opts.no_toast_expansion) + { + /* + * Include a CTE for toast tables associated with primary heap tables + * selected above, filtering by exclusion patterns (if any) that match + * toast table names. + */ + appendPQExpBufferStr(&sql, + ", toast (oid, nspname, relname, relpages) AS (" + "\nSELECT t.oid, 'pg_toast', t.relname, t.relpages" + "\nFROM pg_catalog.pg_class t " + "INNER JOIN relation r " + "ON r.reltoastrelid = t.oid"); + if (opts.excludetbl || opts.excludensp) + appendPQExpBufferStr(&sql, + "\nLEFT OUTER JOIN exclude_pat ep" + "\nON ('pg_toast' ~ ep.nsp_regex OR ep.nsp_regex IS NULL)" + "\nAND (t.relname ~ ep.rel_regex OR ep.rel_regex IS NULL)" + "\nAND ep.heap_only" + "\nWHERE ep.pattern_id IS NULL" + "\nAND t.relpersistence != 't'"); + appendPQExpBufferStr(&sql, + "\n)"); + } + if (!opts.no_btree_expansion) + { + /* + * Include a CTE for btree indexes associated with primary heap tables + * selected above, filtering by exclusion patterns (if any) that match + * btree index names. + */ + appendPQExpBuffer(&sql, + ", index (oid, nspname, relname, relpages) AS (" + "\nSELECT c.oid, r.nspname, c.relname, c.relpages " + "FROM relation r" + "\nINNER JOIN pg_catalog.pg_index i " + "ON r.oid = i.indrelid " + "INNER JOIN pg_catalog.pg_class c " + "ON i.indexrelid = c.oid " + "AND c.relpersistence != 't'"); + if (opts.excludeidx || opts.excludensp) + appendPQExpBufferStr(&sql, + "\nINNER JOIN pg_catalog.pg_namespace n " + "ON c.relnamespace = n.oid" + "\nLEFT OUTER JOIN exclude_pat ep " + "ON (n.nspname ~ ep.nsp_regex OR ep.nsp_regex IS NULL) " + "AND (c.relname ~ ep.rel_regex OR ep.rel_regex IS NULL) " + "AND ep.btree_only" + "\nWHERE ep.pattern_id IS NULL"); + else + appendPQExpBufferStr(&sql, + "\nWHERE true"); + appendPQExpBuffer(&sql, + " AND c.relam = %u " + "AND c.relkind = 'i'", + BTREE_AM_OID); + if (opts.no_toast_expansion) + appendPQExpBuffer(&sql, + " AND c.relnamespace != %u", + PG_TOAST_NAMESPACE); + appendPQExpBufferStr(&sql, "\n)"); + } + + if (!opts.no_toast_expansion && !opts.no_btree_expansion) + { + /* + * Include a CTE for btree indexes associated with toast tables of + * primary heap tables selected above, filtering by exclusion patterns + * (if any) that match the toast index names. + */ + appendPQExpBuffer(&sql, + ", toast_index (oid, nspname, relname, relpages) AS (" + "\nSELECT c.oid, 'pg_toast', c.relname, c.relpages " + "FROM toast t " + "INNER JOIN pg_catalog.pg_index i " + "ON t.oid = i.indrelid" + "\nINNER JOIN pg_catalog.pg_class c " + "ON i.indexrelid = c.oid " + "AND c.relpersistence != 't'"); + if (opts.excludeidx) + appendPQExpBufferStr(&sql, + "\nLEFT OUTER JOIN exclude_pat ep " + "ON ('pg_toast' ~ ep.nsp_regex OR ep.nsp_regex IS NULL) " + "AND (c.relname ~ ep.rel_regex OR ep.rel_regex IS NULL) " + "AND ep.btree_only " + "WHERE ep.pattern_id IS NULL"); + else + appendPQExpBufferStr(&sql, + "\nWHERE true"); + appendPQExpBuffer(&sql, + " AND c.relam = %u" + " AND c.relkind = 'i')", + BTREE_AM_OID); + } + + /* + * Roll-up distinct rows from CTEs. + * + * Relations that match more than one pattern may occur more than once in + * the list, and indexes and toast for primary relations may also have + * matched in their own right, so we rely on UNION to deduplicate the + * list. + */ + appendPQExpBuffer(&sql, + "\nSELECT pattern_id, is_heap, is_btree, oid, nspname, relname, relpages " + "FROM ("); + appendPQExpBufferStr(&sql, + /* Inclusion patterns that failed to match */ + "\nSELECT pattern_id, is_heap, is_btree, " + "NULL::OID AS oid, " + "NULL::TEXT AS nspname, " + "NULL::TEXT AS relname, " + "NULL::INTEGER AS relpages" + "\nFROM relation " + "WHERE pattern_id IS NOT NULL " + "UNION" + /* Primary relations */ + "\nSELECT NULL::INTEGER AS pattern_id, " + "is_heap, is_btree, oid, nspname, relname, relpages " + "FROM relation"); + if (!opts.no_toast_expansion) + appendPQExpBufferStr(&sql, + " UNION" + /* Toast tables for primary relations */ + "\nSELECT NULL::INTEGER AS pattern_id, TRUE AS is_heap, " + "FALSE AS is_btree, oid, nspname, relname, relpages " + "FROM toast"); + if (!opts.no_btree_expansion) + appendPQExpBufferStr(&sql, + " UNION" + /* Indexes for primary relations */ + "\nSELECT NULL::INTEGER AS pattern_id, FALSE AS is_heap, " + "TRUE AS is_btree, oid, nspname, relname, relpages " + "FROM index"); + if (!opts.no_toast_expansion && !opts.no_btree_expansion) + appendPQExpBufferStr(&sql, + " UNION" + /* Indexes for toast relations */ + "\nSELECT NULL::INTEGER AS pattern_id, FALSE AS is_heap, " + "TRUE AS is_btree, oid, nspname, relname, relpages " + "FROM toast_index"); + appendPQExpBufferStr(&sql, + "\n) AS combined_records " + "ORDER BY relpages DESC NULLS FIRST, oid"); + + res = executeQuery(conn, sql.data, opts.echo); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + { + pg_log_error("query failed: %s", PQerrorMessage(conn)); + pg_log_info("query was: %s", sql.data); + disconnectDatabase(conn); + exit(1); + } + termPQExpBuffer(&sql); + + ntups = PQntuples(res); + for (i = 0; i < ntups; i++) + { + int pattern_id = -1; + bool is_heap = false; + bool is_btree PG_USED_FOR_ASSERTS_ONLY = false; + Oid oid = InvalidOid; + const char *nspname = NULL; + const char *relname = NULL; + int relpages = 0; + + if (!PQgetisnull(res, i, 0)) + pattern_id = atoi(PQgetvalue(res, i, 0)); + if (!PQgetisnull(res, i, 1)) + is_heap = (PQgetvalue(res, i, 1)[0] == 't'); + if (!PQgetisnull(res, i, 2)) + is_btree = (PQgetvalue(res, i, 2)[0] == 't'); + if (!PQgetisnull(res, i, 3)) + oid = atooid(PQgetvalue(res, i, 3)); + if (!PQgetisnull(res, i, 4)) + nspname = PQgetvalue(res, i, 4); + if (!PQgetisnull(res, i, 5)) + relname = PQgetvalue(res, i, 5); + if (!PQgetisnull(res, i, 6)) + relpages = atoi(PQgetvalue(res, i, 6)); + + if (pattern_id >= 0) + { + /* + * Current record pertains to an inclusion pattern. Record that + * it matched. + */ + + if (pattern_id >= opts.include.len) + { + pg_log_error("internal error: received unexpected relation pattern_id %d", + pattern_id); + exit(1); + } + + opts.include.data[pattern_id].matched = true; + } + else + { + /* Current record pertains to a relation */ + + RelationInfo *rel = (RelationInfo *) pg_malloc0(sizeof(RelationInfo)); + + Assert(OidIsValid(oid)); + Assert((is_heap && !is_btree) || (is_btree && !is_heap)); + + rel->datinfo = dat; + rel->reloid = oid; + rel->is_heap = is_heap; + rel->nspname = pstrdup(nspname); + rel->relname = pstrdup(relname); + rel->relpages = relpages; + rel->blocks_to_check = relpages; + if (is_heap && (opts.startblock >= 0 || opts.endblock >= 0)) + { + /* + * We apply --startblock and --endblock to heap tables, but + * not btree indexes, and for progress purposes we need to + * track how many blocks we expect to check. + */ + if (opts.endblock >= 0 && rel->blocks_to_check > opts.endblock) + rel->blocks_to_check = opts.endblock + 1; + if (opts.startblock >= 0) + { + if (rel->blocks_to_check > opts.startblock) + rel->blocks_to_check -= opts.startblock; + else + rel->blocks_to_check = 0; + } + } + *pagecount += rel->blocks_to_check; + + simple_ptr_list_append(relations, rel); + } + } + PQclear(res); +} diff --git a/src/bin/pg_amcheck/po/de.po b/src/bin/pg_amcheck/po/de.po new file mode 100644 index 0000000..7bb2111 --- /dev/null +++ b/src/bin/pg_amcheck/po/de.po @@ -0,0 +1,523 @@ +# German message translation file for pg_amcheck +# Copyright (C) 2021 PostgreSQL Global Development Group +# This file is distributed under the same license as the pg_amcheck (PostgreSQL) package. +# +msgid "" +msgstr "" +"Project-Id-Version: pg_amcheck (PostgreSQL) 14\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2022-05-05 22:49+0000\n" +"PO-Revision-Date: 2022-05-06 10:33+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" + +#: ../../../src/common/logging.c:259 +#, c-format +msgid "fatal: " +msgstr "Fatal: " + +#: ../../../src/common/logging.c:266 +#, c-format +msgid "error: " +msgstr "Fehler: " + +#: ../../../src/common/logging.c:273 +#, c-format +msgid "warning: " +msgstr "Warnung: " + +#: ../../fe_utils/cancel.c:189 ../../fe_utils/cancel.c:238 +msgid "Cancel request sent\n" +msgstr "Abbruchsanforderung gesendet\n" + +#: ../../fe_utils/cancel.c:190 ../../fe_utils/cancel.c:239 +msgid "Could not send cancel request: " +msgstr "Konnte Abbruchsanforderung nicht senden: " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "konnte nicht mit Datenbank %s verbinden: Speicher aufgebraucht" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1678 pg_amcheck.c:2126 +#, c-format +msgid "query failed: %s" +msgstr "Anfrage fehlgeschlagen: %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:598 pg_amcheck.c:1128 pg_amcheck.c:1679 pg_amcheck.c:2127 +#, c-format +msgid "query was: %s" +msgstr "Anfrage war: %s" + +#: pg_amcheck.c:330 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "Anzahl paralleler Jobs muss mindestens 1 sein" + +#: pg_amcheck.c:402 +#, c-format +msgid "invalid argument for option %s" +msgstr "ungültiges Argument für Option %s" + +#: pg_amcheck.c:411 +#, c-format +msgid "invalid start block" +msgstr "ungültiger Startblock" + +#: pg_amcheck.c:416 +#, c-format +msgid "start block out of bounds" +msgstr "Startblock außerhalb des gültigen Bereichs" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "ungültiger Endblock" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "Endblock außerhalb des gültigen Bereichs" + +#: pg_amcheck.c:456 pg_amcheck.c:482 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" + +#: pg_amcheck.c:464 +#, c-format +msgid "end block precedes start block" +msgstr "Endblock kommt vor dem Startblock" + +#: pg_amcheck.c:480 +#, c-format +msgid "too many command-line arguments (first is \"%s\")" +msgstr "zu viele Kommandozeilenargumente (das erste ist »%s«)" + +#: pg_amcheck.c:501 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "ein Datenbankname kann nicht mit --all angegeben werden" + +#: pg_amcheck.c:510 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "Datenbankname und Datenbankmuster können nicht zusammen angegeben werden" + +#: pg_amcheck.c:540 +#, c-format +msgid "no databases to check" +msgstr "keine zu prüfenden Datenbanken" + +#: pg_amcheck.c:596 +#, c-format +msgid "database \"%s\": %s" +msgstr "Datenbank »%s«: %s" + +#: pg_amcheck.c:607 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "Datenbank »%s« übersprungen: amcheck nicht installiert" + +#: pg_amcheck.c:615 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "in Datenbank »%s«: verwende amcheck Version »%s« in Schema »%s«" + +#: pg_amcheck.c:637 +#, c-format +msgid "no heap tables to check matching \"%s\"" +msgstr "keine zu prüfenden Tabellen, die mit »%s« übereinstimmen" + +#: pg_amcheck.c:640 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "keine zu prüfenden B-Tree-Indexe, die mit »%s« übereinstimmen" + +#: pg_amcheck.c:643 +#, c-format +msgid "no relations to check in schemas matching \"%s\"" +msgstr "keine zu prüfenden Relationen in Schemas, die mit »%s« übereinstimmen" + +#: pg_amcheck.c:646 +#, c-format +msgid "no relations to check matching \"%s\"" +msgstr "keine zu prüfenden Relationen, die mit »%s« übereinstimmen" + +#: pg_amcheck.c:674 +#, c-format +msgid "no relations to check" +msgstr "keine zu prüfenden Relationen" + +#: pg_amcheck.c:758 +#, c-format +msgid "checking heap table \"%s.%s.%s\"" +msgstr "prüfe Heap-Tabelle »%s.%s.%s«" + +#: pg_amcheck.c:774 +#, c-format +msgid "checking btree index \"%s.%s.%s\"" +msgstr "prüfe B-Tree-Index »%s.%s.%s«" + +#: pg_amcheck.c:921 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "Fehler beim Senden von Befehl an Datenbank »%s«: %s" + +#: pg_amcheck.c:924 +#, c-format +msgid "command was: %s" +msgstr "Befehl war: %s" + +#: pg_amcheck.c:1041 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "Heap-Tabelle »%s.%s.%s«, Block %s, Offset %s, Attribut %s:\n" + +#: pg_amcheck.c:1048 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "Heap-Tabelle »%s.%s.%s«, Block %s, Offset %s:\n" + +#: pg_amcheck.c:1054 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "Heap-Tabelle »%s.%s.%s«, Block %s:\n" + +#: pg_amcheck.c:1059 pg_amcheck.c:1070 +#, c-format +msgid "heap table \"%s.%s.%s\":\n" +msgstr "Heap-Tabelle »%s.%s.%s«:\n" + +#: pg_amcheck.c:1074 pg_amcheck.c:1143 +#, c-format +msgid "query was: %s\n" +msgstr "Anfrage war: %s\n" + +#: pg_amcheck.c:1125 +#, c-format +msgid "btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d" +msgstr "B-Tree-Index »%s.%s.%s«: B-Tree-Prüffunktion gab unerwartete Anzahl Zeilen zurück: %d" + +#: pg_amcheck.c:1129 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "Sind die Versionen von %s und amcheck kompatibel?" + +#: pg_amcheck.c:1139 +#, c-format +msgid "btree index \"%s.%s.%s\":\n" +msgstr "B-Tree-Index »%s.%s.%s«:\n" + +#: pg_amcheck.c:1164 +#, c-format +msgid "" +"%s checks objects in a PostgreSQL database for corruption.\n" +"\n" +msgstr "" +"%s prüft Objekte in einer PostgreSQL-Datenbank auf Beschädigung.\n" +"\n" + +#: pg_amcheck.c:1165 +#, c-format +msgid "Usage:\n" +msgstr "Aufruf:\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [OPTION]... [DBNAME]\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid "" +"\n" +"Target options:\n" +msgstr "" +"\n" +"Zieloptionen:\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all alle Datenbanken prüfen\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr " -d, --database=MUSTER übereinstimmende Datenbanken prüfen\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr " -D, --exclude-database=MUSTER übereinstimmende Datenbanken NICHT prüfen\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr " -i, --index=MUSTER übereinstimmende Indexe prüfen\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr " -I, --exclude-index=MUSTER übereinstimmende Indexe NICHT prüfen\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr " -r, --relation=MUSTER übereinstimmende Relationen prüfen\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr " -R, --exclude-relation=MUSTER übereinstimmende Relationen NICHT prüfen\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr " -s, --schema=MUSTER übereinstimmende Schemas prüfen\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr " -S, --exclude-schema=MUSTER übereinstimmende Schemas NICHT prüfen\n" + +#: pg_amcheck.c:1177 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr " -t, --table=MUSTER übereinstimmende Tabellen prüfen\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr " -T, --exclude-table=MUSTER übereinstimmende Tabellen NICHT prüfen\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid " --no-dependent-indexes do NOT expand list of relations to include indexes\n" +msgstr " --no-dependent-indexes Liste der Relationen NICHT um Indexe erweitern\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid " --no-dependent-toast do NOT expand list of relations to include TOAST tables\n" +msgstr " --no-dependent-toast Liste der Relationen NICHT um TOAST-Tabellen erweitern\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid " --no-strict-names do NOT require patterns to match objects\n" +msgstr " --no-strict-names Muster müssen NICHT mit Objekten übereinstimmen\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid "" +"\n" +"Table checking options:\n" +msgstr "" +"\n" +"Optionen für Tabellen:\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid " --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr " --exclude-toast-pointers TOAST-Zeigern NICHT folgen\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid " --on-error-stop stop checking at end of first corrupt page\n" +msgstr " --on-error-stop Prüfung nach der ersten beschädigten Seite beenden\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid " --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n" +msgstr " --skip=OPTION Blöcke mit »all-frozen« oder »all-visible« NICHT prüfen\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid " --startblock=BLOCK begin checking table(s) at the given block number\n" +msgstr " --startblock=BLOCK Prüfen der Tabelle(n) bei angegebener Blocknummer beginnen\n" + +#: pg_amcheck.c:1187 +#, c-format +msgid " --endblock=BLOCK check table(s) only up to the given block number\n" +msgstr " --endblock=BLOCK Tabelle(n) nur bis zur angegebenen Blocknummer prüfen\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid "" +"\n" +"B-tree index checking options:\n" +msgstr "" +"\n" +"Optionen für B-Tree-Indexe:\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid " --heapallindexed check that all heap tuples are found within indexes\n" +msgstr " --heapallindexed prüfen, dass alle Heap-Tupel in Indexen zu finden sind\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid " --parent-check check index parent/child relationships\n" +msgstr " --parent-check Index-Eltern/Kind-Beziehungen prüfen\n" + +#: pg_amcheck.c:1191 +#, c-format +msgid " --rootdescend search from root page to refind tuples\n" +msgstr " --rootdescend Tupel erneut von der Wurzelseite aus suchen\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid "" +"\n" +"Connection options:\n" +msgstr "" +"\n" +"Verbindungsoptionen:\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid " -h, --host=HOSTNAME database server host or socket directory\n" +msgstr " -h, --host=HOSTNAME Name des Datenbankservers oder Socket-Verzeichnis\n" + +#: pg_amcheck.c:1194 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=PORT Port des Datenbankservers\n" + +#: pg_amcheck.c:1195 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr " -U, --username=NAME Datenbankbenutzername\n" + +#: pg_amcheck.c:1196 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password niemals nach Passwort fragen\n" + +#: pg_amcheck.c:1197 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password Passwortfrage erzwingen\n" + +#: pg_amcheck.c:1198 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=DBNAME alternative Wartungsdatenbank\n" + +#: pg_amcheck.c:1199 +#, c-format +msgid "" +"\n" +"Other options:\n" +msgstr "" +"\n" +"Weitere Optionen:\n" + +#: pg_amcheck.c:1200 +#, c-format +msgid " -e, --echo show the commands being sent to the server\n" +msgstr "" +" -e, --echo zeige die Befehle, die an den Server\n" +" gesendet werden\n" + +#: pg_amcheck.c:1201 +#, c-format +msgid " -j, --jobs=NUM use this many concurrent connections to the server\n" +msgstr "" +" -j, --jobs=NUM so viele parallele Verbindungen zum Server\n" +" verwenden\n" + +#: pg_amcheck.c:1202 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress Fortschrittsinformationen zeigen\n" + +#: pg_amcheck.c:1203 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose erzeuge viele Meldungen\n" + +#: pg_amcheck.c:1204 +#, c-format +msgid " -V, --version output version information, then exit\n" +msgstr " -V, --version Versionsinformationen anzeigen, dann beenden\n" + +#: pg_amcheck.c:1205 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing fehlende Erweiterungen installieren\n" + +#: pg_amcheck.c:1206 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help diese Hilfe anzeigen, dann beenden\n" + +#: pg_amcheck.c:1208 +#, c-format +msgid "" +"\n" +"Report bugs to <%s>.\n" +msgstr "" +"\n" +"Berichten Sie Fehler an <%s>.\n" + +#: pg_amcheck.c:1209 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "%s Homepage: <%s>\n" + +#: pg_amcheck.c:1267 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "%*s/%s Relationen (%d%%), %*s/%s Seiten (%d%%) %*s" + +#: pg_amcheck.c:1278 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "%*s/%s Relationen (%d%%), %*s/%s Seiten (%d%%) (%s%-*.*s)" + +#: pg_amcheck.c:1293 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "%*s/%s Relationen (%d%%), %*s/%s Seiten (%d%%)" + +#: pg_amcheck.c:1352 pg_amcheck.c:1385 +#, c-format +msgid "improper qualified name (too many dotted names): %s" +msgstr "falscher qualifizierter Name (zu viele Namensteile): %s" + +#: pg_amcheck.c:1430 +#, c-format +msgid "improper relation name (too many dotted names): %s" +msgstr "falscher Relationsname (zu viele Namensteile): %s" + +#: pg_amcheck.c:1583 pg_amcheck.c:1725 +#, c-format +msgid "including database \"%s\"" +msgstr "Datenbank »%s« einbezogen" + +#: pg_amcheck.c:1705 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "interner Fehler: unerwartete pattern_id %d für Datenbank empfangen" + +#: pg_amcheck.c:1709 +#, c-format +msgid "no connectable databases to check matching \"%s\"" +msgstr "keine Datenbanken, mit denen verbunden werden kann und die mit »%s« übereinstimmen" + +#: pg_amcheck.c:2168 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "interner Fehler: unerwartete pattern_id %d für Relation empfangen" diff --git a/src/bin/pg_amcheck/po/el.po b/src/bin/pg_amcheck/po/el.po new file mode 100644 index 0000000..e9b4fca --- /dev/null +++ b/src/bin/pg_amcheck/po/el.po @@ -0,0 +1,516 @@ +# Greek message translation file for pg_amcheck +# Copyright (C) 2021 PostgreSQL Global Development Group +# This file is distributed under the same license as the pg_amcheck (PostgreSQL) package. +# Georgios Kokolatos <gkokolatos@pm.me>, 2021. +# +# +# +msgid "" +msgstr "" +"Project-Id-Version: pg_amcheck (PostgreSQL) 14\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2021-11-08 10:17+0000\n" +"PO-Revision-Date: 2021-11-08 11:49+0100\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" +"X-Generator: Poedit 3.0\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 "προειδοποίηση: " + +#: ../../fe_utils/cancel.c:161 ../../fe_utils/cancel.c:206 +msgid "Cancel request sent\n" +msgstr "Αίτηση ακύρωσης εστάλη\n" + +#: ../../fe_utils/cancel.c:165 ../../fe_utils/cancel.c:210 +msgid "Could not send cancel request: " +msgstr "Δεν ήταν δυνατή η αποστολή αίτησης ακύρωσης: " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "δεν ήταν δυνατή η σύνδεση με τη βάσης δεδομένων %s: έλλειψη μνήμης" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1657 pg_amcheck.c:2105 +#, c-format +msgid "query failed: %s" +msgstr "το ερώτημα απέτυχε: %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:598 pg_amcheck.c:1128 pg_amcheck.c:1658 pg_amcheck.c:2106 +#, c-format +msgid "query was: %s" +msgstr "το ερώτημα ήταν: %s" + +#: pg_amcheck.c:330 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "ο αριθμός παράλληλων εργασιών πρέπει να είναι τουλάχιστον 1" + +#: pg_amcheck.c:402 +#, c-format +msgid "invalid argument for option %s" +msgstr "μη έγκυρη παράμετρος για την επιλογή %s" + +#: pg_amcheck.c:411 +#, c-format +msgid "invalid start block" +msgstr "μη έγκυρο μπλοκ εκκίνησης" + +#: pg_amcheck.c:416 +#, c-format +msgid "start block out of bounds" +msgstr "μπλοκ εκκίνησης εκτός ορίων" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "μη έγκυρο μπλοκ τερματισμού" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "μπλοκ τερματισμού εκτός ορίων" + +#: pg_amcheck.c:456 pg_amcheck.c:482 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "Δοκιμάστε «%s --help» για περισσότερες πληροφορίες.\n" + +#: pg_amcheck.c:464 +#, c-format +msgid "end block precedes start block" +msgstr "μπλοκ τερματισμού προηγείται του μπλοκ εκκίνησης" + +#: pg_amcheck.c:480 +#, c-format +msgid "too many command-line arguments (first is \"%s\")" +msgstr "πάρα πολλές παράμετροι εισόδου από την γραμμή εντολών (η πρώτη είναι η «%s»)" + +#: pg_amcheck.c:501 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "δεν είναι δυνατό να οριστεί ένα όνομα βάσης δεδομένων μαζί με --all" + +#: pg_amcheck.c:510 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "δεν είναι δυνατός ο καθορισμός τόσο ενός ονόματος βάσης δεδομένων όσο και μοτίβων βάσης δεδομένων" + +#: pg_amcheck.c:540 +#, c-format +msgid "no databases to check" +msgstr "καθόλου βάσεις δεδομένων για έλεγχο" + +#: pg_amcheck.c:596 +#, c-format +msgid "database \"%s\": %s" +msgstr "βάση δεδομένων «%s»: %s" + +#: pg_amcheck.c:607 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "παρακάμπτει βάση δεδομένων «%s»: το amcheck δεν είναι εγκαταστημένο" + +#: pg_amcheck.c:615 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "στη βάση δεδομένων «%s»: χρησιμοποιώντας την έκδοση «%s» του amcheck στο σχήμα «%s»" + +#: pg_amcheck.c:637 +#, c-format +msgid "no heap tables to check matching \"%s\"" +msgstr "δεν υπάρχουν πίνακες heap για έλεγχο που ταιριάζουν με «%s»" + +#: pg_amcheck.c:640 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "δεν υπάρχουν ευρετήρια BTREE για έλεγχο που ταιριάζουν με «%s»" + +#: pg_amcheck.c:643 +#, c-format +msgid "no relations to check in schemas matching \"%s\"" +msgstr "καθόλου σχέσεις για έλεγχο σε σχήματα που ταιριάζουν με «%s»" + +#: pg_amcheck.c:646 +#, c-format +msgid "no relations to check matching \"%s\"" +msgstr "καθόλου σχέσεις για έλεγχο που ταιριάζουν με «%s»" + +#: pg_amcheck.c:674 +#, c-format +msgid "no relations to check" +msgstr "καθόλου σχέσεις για έλεγχο" + +#: pg_amcheck.c:758 +#, c-format +msgid "checking heap table \"%s.%s.%s\"" +msgstr "ελέγχει τον πίνακα heap «%s.%s.%s»" + +#: pg_amcheck.c:774 +#, c-format +msgid "checking btree index \"%s.%s.%s\"" +msgstr "ελέγχει το ευρετήριο btree «%s.%s.%s»" + +#: pg_amcheck.c:921 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "εντολή αποστολής σφάλματος στη βάση δεδομένων «%s»: %s" + +#: pg_amcheck.c:924 +#, c-format +msgid "command was: %s" +msgstr "η εντολή ήταν: %s" + +#: pg_amcheck.c:1041 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "πίνακας heap «%s.%s.%s», μπλοκ %s, μετατόπιση %s, χαρακτηριστικό %s:\n" + +#: pg_amcheck.c:1048 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "πίνακας heap «%s.%s.%s», μπλοκ %s, μετατόπιση %s:\n" + +#: pg_amcheck.c:1054 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "πίνακας heap «%s.%s.%s», μπλοκ %s:\n" + +#: pg_amcheck.c:1059 pg_amcheck.c:1070 +#, c-format +msgid "heap table \"%s.%s.%s\":\n" +msgstr "πίνακας heap «%s.%s.%s»:\n" + +#: pg_amcheck.c:1074 pg_amcheck.c:1143 +#, c-format +msgid "query was: %s\n" +msgstr "το ερώτημα ήταν: %s\n" + +#: pg_amcheck.c:1125 +#, c-format +msgid "btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d" +msgstr "ευρετήριο btree «%s.%s.%s»: η συνάρτηση ελέγχου btree επέστρεψε απροσδόκητο αριθμό γραμμών: %d" + +#: pg_amcheck.c:1129 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "Είναι συμβατές οι εκδόσεις του %s και του amcheck;" + +#: pg_amcheck.c:1139 +#, c-format +msgid "btree index \"%s.%s.%s\":\n" +msgstr "ευρετήριο btree «%s.%s.%s»:\n" + +#: pg_amcheck.c:1164 +#, c-format +msgid "" +"%s checks objects in a PostgreSQL database for corruption.\n" +"\n" +msgstr "" +"%s ελέγχει αντικείμενα σε μια βάση δεδομένων PostgreSQL για αλλοίωση.\n" +"\n" + +#: pg_amcheck.c:1165 +#, c-format +msgid "Usage:\n" +msgstr "Χρήση:\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [ΕΠΙΛΟΓΗ]... [DBNAME]\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid "" +"\n" +"Target options:\n" +msgstr "" +"\n" +"Επιλογές στόχου:\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all έλεγξε όλες τις βάσεις δεδομένων\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr " -d, --database=PATTERN έλεγξε ταιριαστή(-ες) με το μοτίβο βάση(-εις) δεδομένων\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr " -D, --exclude-database=PATTERN να ΜΗΝ ελέγξει ταιριαστή(-ες) με το μοτίβο βάση(-εις) δεδομένων\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr " -i, --index=PATTERN έλεγξε ταιριαστό(-ά) με το μοτίβο ευρετήριο(-ά)\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr " -I, --exclude-index=PATTERN να ΜΗΝ ελέγξει ταιριαστό(-ά) με το μοτίβο ευρετήριο(-ά)\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr " -i, --index=PATTERN έλεγξε ταιριαστή(-ές) με το μοτίβο σχέση(-εις)\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr " -R, --exclude-relation=PATTERN να ΜΗΝ ελέγξει ταιριαστή(-ές) με το μοτίβο σχέση(-εις)\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr " -s, --schema=PATTERN έλεγξε ταιριαστό(-ά) με το μοτίβο σχήμα(-τα)\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr " -S, --exclude-schema=PATTERN να ΜΗΝ ελέγξει ταιριαστό(-ά) με το μοτίβο σχήμα(-τα)\n" + +#: pg_amcheck.c:1177 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr " -t, --table=PATTERN έλεγξε ταιριαστό(-ούς) με το μοτίβο πίνακα(-ες)\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr " -T, --exclude-table=PATTERN να ΜΗΝ ελέγξει ταιριαστό(-ούς) με το μοτίβο πίνακα(-ες)\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid " --no-dependent-indexes do NOT expand list of relations to include indexes\n" +msgstr " --no-dependent-indexes να ΜΗΝ επεκτείνεις τη λίστα σχέσεων ώστε να συμπεριλάβει ευρετήρια\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid " --no-dependent-toast do NOT expand list of relations to include TOAST tables\n" +msgstr " --no-dependent-toast να ΜΗΝ επεκτείνεις τη λίστα σχέσεων ώστε να συμπεριλάβει πίνακες TOAST\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid " --no-strict-names do NOT require patterns to match objects\n" +msgstr " --no-strict-names να ΜΗΝ απαιτήσει μοτίβα για την αντιστοίχιση αντικειμένων\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid "" +"\n" +"Table checking options:\n" +msgstr "" +"\n" +"Επιλογές ελέγχου πίνακα:\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid " --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr " --exclude-toast-pointers να ΜΗΝ ακολουθήσει τους δείκτες σχέσεων TOAST\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid " --on-error-stop stop checking at end of first corrupt page\n" +msgstr " --on-error-stop διακοπή ελέγχου στο τέλος της πρώτης αλλοιωμένης σελίδας\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid " --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n" +msgstr " --skip=OPTION να ΜΗΝ ελέγξει τα «all-frozen» ή «all-visible» μπλοκ\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid " --startblock=BLOCK begin checking table(s) at the given block number\n" +msgstr " --startblock=BLOCK εκκίνηση του ελέγχου πίνακα(-ων) από τον δοσμένο αριθμό μπλοκ\n" + +#: pg_amcheck.c:1187 +#, c-format +msgid " --endblock=BLOCK check table(s) only up to the given block number\n" +msgstr " --endblock=BLOCK τερματισμός του ελέγχου πίνακα(-ων) από τον δοσμένο αριθμό μπλοκ\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid "" +"\n" +"B-tree index checking options:\n" +msgstr "" +"\n" +"Επιλογές ελέγχου ευρετηρίου B-tree:\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid " --heapallindexed check that all heap tuples are found within indexes\n" +msgstr " --heapallindexed έλεγξε ότι όλες οι πλειάδες heap περιλαμβάνονται σε ευρετήρια\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid " --parent-check check index parent/child relationships\n" +msgstr " --parent-check έλεγξε σχέσεις γονέα/απογόνου ευρετηρίου\n" + +#: pg_amcheck.c:1191 +#, c-format +msgid " --rootdescend search from root page to refind tuples\n" +msgstr " --rootdescend αναζήτησε από τη ριζική σελίδα για την επανεύρεση πλειάδων\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid "" +"\n" +"Connection options:\n" +msgstr "" +"\n" +"Επιλογές σύνδεσης:\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid " -h, --host=HOSTNAME database server host or socket directory\n" +msgstr " -h, --host=HOSTNAME διακομιστής βάσης δεδομένων ή κατάλογος υποδοχών\n" + +#: pg_amcheck.c:1194 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=PORT θύρα διακομιστή βάσης δεδομένων\n" + +#: pg_amcheck.c:1195 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr " -U, --username=USERNAME όνομα χρήστη με το οποίο να συνδεθεί\n" + +#: pg_amcheck.c:1196 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password να μην ζητείται ποτέ κωδικός πρόσβασης\n" + +#: pg_amcheck.c:1197 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password αναγκαστική προτροπή κωδικού πρόσβασης\n" + +#: pg_amcheck.c:1198 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=DBNAME εναλλακτική βάση δεδομένων συντήρησης\n" + +#: pg_amcheck.c:1199 +#, c-format +msgid "" +"\n" +"Other options:\n" +msgstr "" +"\n" +"Άλλες επιλογές:\n" + +#: pg_amcheck.c:1200 +#, c-format +msgid " -e, --echo show the commands being sent to the server\n" +msgstr " -e, --echo εμφάνισε τις εντολές που αποστέλλονται στο διακομιστή\n" + +#: pg_amcheck.c:1201 +#, c-format +msgid " -j, --jobs=NUM use this many concurrent connections to the server\n" +msgstr " -j, --jobs=NUM χρησιμοποιήσε τόσες πολλές ταυτόχρονες συνδέσεις με το διακομιστή\n" + +#: pg_amcheck.c:1202 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress εμφάνισε πληροφορίες προόδου\n" + +#: pg_amcheck.c:1203 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose γράψε πολλά μηνύματα εξόδου\n" + +#: pg_amcheck.c:1204 +#, c-format +msgid " -V, --version output version information, then exit\n" +msgstr " -V, --version εμφάνισε πληροφορίες έκδοσης, στη συνέχεια έξοδος\n" + +#: pg_amcheck.c:1205 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing εγκατάστησε επεκτάσεις που λείπουν\n" + +#: pg_amcheck.c:1206 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help εμφάνισε αυτό το μήνυμα βοήθειας, στη συνέχεια έξοδος\n" + +#: pg_amcheck.c:1208 +#, c-format +msgid "" +"\n" +"Report bugs to <%s>.\n" +msgstr "" +"\n" +"Υποβάλετε αναφορές σφάλματων σε <%s>.\n" + +#: pg_amcheck.c:1209 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "%s αρχική σελίδα: <%s>\n" + +#: pg_amcheck.c:1267 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "%*s/%s σχέσεις (%d%%), %*s/%s σελίδες (%d%%) %*s" + +#: pg_amcheck.c:1278 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "%*s/%s σχέσεις (%d%%), %*s/%s σελίδες (%d%%) (%s%-*.*s)" + +#: pg_amcheck.c:1293 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "%*s/%s σχέσεις (%d%%), %*s/%s σελίδες (%d%%)" + +#: pg_amcheck.c:1562 pg_amcheck.c:1704 +#, c-format +msgid "including database \"%s\"" +msgstr "συμπεριλαμβανομένης της βάσης δεδομένων «%s»" + +#: pg_amcheck.c:1684 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "εσωτερικό σφάλμα: ελήφθη μη αναμενόμενο pattern_id %d" + +#: pg_amcheck.c:1688 +#, c-format +msgid "no connectable databases to check matching \"%s\"" +msgstr "δεν υπάρχουν βάσεις δεδομένων με δυνατότητα σύνδεσης για έλεγχο που να ταιριάζουν με «%s»" + +#: pg_amcheck.c:2147 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "εσωτερικό σφάλμα: ελήφθη μη αναμενόμενο pattern_id σχέσης %d" + +#~ msgid " -q, --quiet don't write any messages\n" +#~ msgstr " -q, --quiet να μην γράψεις κανένα μήνυμα\n" diff --git a/src/bin/pg_amcheck/po/es.po b/src/bin/pg_amcheck/po/es.po new file mode 100644 index 0000000..b5df139 --- /dev/null +++ b/src/bin/pg_amcheck/po/es.po @@ -0,0 +1,523 @@ +# Spanish translation file for pg_amcheck +# +# Copyright (C) 2021 PostgreSQL Global Development Group +# This file is distributed under the same license as the pg_amcheck (PostgreSQL) package. +# +# Carlos Chapi <carloswaldo@babelruins.org>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: pg_amcheck (PostgreSQL) 14\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2022-08-07 20:35+0000\n" +"PO-Revision-Date: 2021-10-13 23:57-0500\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: BlackCAT 1.1\n" + +#: ../../../src/common/logging.c:259 +#, c-format +msgid "fatal: " +msgstr "fatal: " + +#: ../../../src/common/logging.c:266 +#, c-format +msgid "error: " +msgstr "error: " + +#: ../../../src/common/logging.c:273 +#, c-format +msgid "warning: " +msgstr "precaución: " + +#: ../../fe_utils/cancel.c:189 ../../fe_utils/cancel.c:238 +msgid "Cancel request sent\n" +msgstr "Petición de cancelación enviada\n" + +#: ../../fe_utils/cancel.c:190 ../../fe_utils/cancel.c:239 +msgid "Could not send cancel request: " +msgstr "No se pudo enviar la petición de cancelación: " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "no se pudo conectar a la base de datos %s: memoria agotada" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1680 pg_amcheck.c:2128 +#, c-format +msgid "query failed: %s" +msgstr "la consulta falló: %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:598 pg_amcheck.c:1130 pg_amcheck.c:1681 pg_amcheck.c:2129 +#, c-format +msgid "query was: %s" +msgstr "la consulta era: %s" + +#: pg_amcheck.c:330 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "número de trabajos en paralelo debe ser al menos 1" + +#: pg_amcheck.c:402 +#, c-format +msgid "invalid argument for option %s" +msgstr "argumento no válido para la opción %s" + +#: pg_amcheck.c:411 +#, c-format +msgid "invalid start block" +msgstr "bloque de inicio no válido" + +#: pg_amcheck.c:416 +#, c-format +msgid "start block out of bounds" +msgstr "bloque de inicio fuera de rango" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "bloque final no válido" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "bloque final fuera de rango" + +#: pg_amcheck.c:456 pg_amcheck.c:482 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "Pruebe «%s --help» para mayor información.\n" + +#: pg_amcheck.c:464 +#, c-format +msgid "end block precedes start block" +msgstr "bloque final precede al bloque de inicio" + +#: pg_amcheck.c:480 +#, 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_amcheck.c:501 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "no se puede especificar un nombre de base de datos al usar --all" + +#: pg_amcheck.c:510 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "no se puede especificar al mismo tiempo un nombre de base de datos junto con patrones de bases de datos" + +#: pg_amcheck.c:540 +#, c-format +msgid "no databases to check" +msgstr "no hay bases de datos para revisar" + +#: pg_amcheck.c:596 +#, c-format +msgid "database \"%s\": %s" +msgstr "base de datos «%s»: %s" + +#: pg_amcheck.c:607 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "omitiendo la base de datos «%s»: amcheck no está instalado" + +#: pg_amcheck.c:615 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "en base de datos «%s»: usando amcheck versión «%s» en esquema «%s»" + +#: pg_amcheck.c:637 +#, c-format +msgid "no heap tables to check matching \"%s\"" +msgstr "no hay tablas heap para revisar que coincidan con «%s»" + +#: pg_amcheck.c:640 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "no hay índices btree para revisar que coincidan con «%s»" + +#: pg_amcheck.c:643 +#, c-format +msgid "no relations to check in schemas matching \"%s\"" +msgstr "no hay relaciones para revisar en esquemas que coincidan con «%s»" + +#: pg_amcheck.c:646 +#, c-format +msgid "no relations to check matching \"%s\"" +msgstr "no hay relaciones para revisar que coincidan con «%s»" + +#: pg_amcheck.c:674 +#, c-format +msgid "no relations to check" +msgstr "no hay relaciones para revisar" + +#: pg_amcheck.c:758 +#, c-format +msgid "checking heap table \"%s.%s.%s\"" +msgstr "revisando tabla heap «%s.%s.%s»" + +#: pg_amcheck.c:774 +#, c-format +msgid "checking btree index \"%s.%s.%s\"" +msgstr "revisando índice btree «%s.%s.%s»" + +#: pg_amcheck.c:921 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "error al enviar orden a la base de datos «%s»: %s" + +#: pg_amcheck.c:924 +#, c-format +msgid "command was: %s" +msgstr "la orden era: %s" + +#: pg_amcheck.c:1043 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "tabla heap «%s.%s.%s», bloque %s, posición %s, atributo %s:\n" + +#: pg_amcheck.c:1050 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "tabla heap «%s.%s.%s», bloque %s, posición %s:\n" + +#: pg_amcheck.c:1056 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "tabla heap «%s.%s.%s», bloque %s:\n" + +#: pg_amcheck.c:1061 pg_amcheck.c:1072 +#, c-format +msgid "heap table \"%s.%s.%s\":\n" +msgstr "tabla heap «%s.%s.%s»:\n" + +#: pg_amcheck.c:1076 pg_amcheck.c:1145 +#, c-format +msgid "query was: %s\n" +msgstr "la consulta era: %s\n" + +#: pg_amcheck.c:1127 +#, c-format +msgid "btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d" +msgstr "índice btree «%s.%s.%s»: la función de comprobación de btree devolvió un número inesperado de registros: %d" + +#: pg_amcheck.c:1131 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "¿Son compatibles la versión de %s con la de amcheck?" + +#: pg_amcheck.c:1141 +#, c-format +msgid "btree index \"%s.%s.%s\":\n" +msgstr "índice btree «%s.%s.%s»:\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid "" +"%s checks objects in a PostgreSQL database for corruption.\n" +"\n" +msgstr "" +"%s busca corrupción en objetos de una base de datos PostgreSQL.\n" +"\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid "Usage:\n" +msgstr "Empleo:\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [OPCIÓN]... [BASE-DE-DATOS]\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid "" +"\n" +"Target options:\n" +msgstr "" +"\n" +"Opciones de objetivo:\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all revisar todas las bases de datos\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr " -d, --database=PATRÓN revisar la(s) base(s) de datos que coincida(n)\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr " -D, --exclude-database=PATRÓN NO revisar la(s) base(s) de datos que coincida(n)\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr " -i, --index=PATRÓN revisar el(los) índice(s) que coincida(n)\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr " -I, --exclude-index=PATRÓN NO revisar el(los) índice(s) que coincida(n)\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr " -r, --relation=PATRÓN revisar la(s) relación(es) que coincida(n)\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr " -R, --exclude-relation=PATRÓN NO revisar la(s) relación(es) que coincida(n)\n" + +#: pg_amcheck.c:1177 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr " -s, --schema=PATRÓN revisar el(los) esquema(s) que coincida(n)\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr " -S, --exclude-schema=PATRÓN NO revisar el(los) esquema(s) que coincida(n)\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr " -t, --table=PATRÓN revisar la(s) tabla(s) que coincida(n)\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr " -T, --exclude-table=PATRÓN NO revisar la(s) tabla(s) que coincida(n)\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid " --no-dependent-indexes do NOT expand list of relations to include indexes\n" +msgstr " --no-dependent-indexes NO expandir la lista de relaciones para incluir índices\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid " --no-dependent-toast do NOT expand list of relations to include TOAST tables\n" +msgstr " --no-dependent-toast NO expandir lista de relaciones para incluir tablas TOAST\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid " --no-strict-names do NOT require patterns to match objects\n" +msgstr " --no-strict-names NO requerir que los patrones coincidan con los objetos\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid "" +"\n" +"Table checking options:\n" +msgstr "" +"\n" +"Opciones para revisión de tabla:\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid " --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr " --exclude-toast-pointers NO seguir punteros TOAST de la relación\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid " --on-error-stop stop checking at end of first corrupt page\n" +msgstr " --on-error-stop detener la revisión al final de la primera página corrupta\n" + +#: pg_amcheck.c:1187 +#, c-format +msgid " --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n" +msgstr " --skip=OPTION NO revisar bloques «all-frozen» u «all-visible»\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid " --startblock=BLOCK begin checking table(s) at the given block number\n" +msgstr " --startblock=BLOQUE empezar la revisión de la(s) tabla(s) en el número de bloque especificado\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid " --endblock=BLOCK check table(s) only up to the given block number\n" +msgstr " --endblock=BLOQUE solo revisar la(s) tabla(s) hasta el número de bloque especificado\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid "" +"\n" +"B-tree index checking options:\n" +msgstr "" +"\n" +"Opciones para revisión de índices B-tree:\n" + +#: pg_amcheck.c:1191 +#, c-format +msgid " --heapallindexed check that all heap tuples are found within indexes\n" +msgstr " --heapallindexed revisar que todas las tuplas heap se encuentren en los índices\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid " --parent-check check index parent/child relationships\n" +msgstr " --parent-check revisar relaciones padre/hijo de índice\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid " --rootdescend search from root page to refind tuples\n" +msgstr " --rootdescend buscar desde la página raíz para volver a encontrar tuplas\n" + +#: pg_amcheck.c:1194 +#, c-format +msgid "" +"\n" +"Connection options:\n" +msgstr "" +"\n" +"Opciones de conexión:\n" + +#: pg_amcheck.c:1195 +#, c-format +msgid " -h, --host=HOSTNAME database server host or socket directory\n" +msgstr " -h, --host=ANFITRIÓN nombre del servidor o directorio del socket\n" + +#: pg_amcheck.c:1196 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=PUERTO puerto del servidor de base de datos\n" + +#: pg_amcheck.c:1197 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr " -U, --username=USUARIO nombre de usuario para la conexión\n" + +#: pg_amcheck.c:1198 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password nunca pedir contraseña\n" + +#: pg_amcheck.c:1199 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password forzar la petición de contraseña\n" + +#: pg_amcheck.c:1200 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=BASE base de datos de mantención alternativa\n" + +#: pg_amcheck.c:1201 +#, c-format +msgid "" +"\n" +"Other options:\n" +msgstr "" +"\n" +"Otras opciones:\n" + +#: pg_amcheck.c:1202 +#, c-format +msgid " -e, --echo show the commands being sent to the server\n" +msgstr " -e, --echo mostrar las órdenes enviadas al servidor\n" + +#: pg_amcheck.c:1203 +#, c-format +msgid " -j, --jobs=NUM use this many concurrent connections to the server\n" +msgstr " -j, --jobs=NUM usar esta cantidad de conexiones concurrentes hacia el servidor\n" + +#: pg_amcheck.c:1204 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress mostrar información de progreso\n" + +#: pg_amcheck.c:1205 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose desplegar varios mensajes informativos\n" + +#: pg_amcheck.c:1206 +#, c-format +msgid " -V, --version output version information, then exit\n" +msgstr " -V, --version mostrar información de versión y salir\n" + +#: pg_amcheck.c:1207 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing instalar extensiones faltantes\n" + +#: pg_amcheck.c:1208 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help mostrar esta ayuda y salir\n" + +#: pg_amcheck.c:1210 +#, c-format +msgid "" +"\n" +"Report bugs to <%s>.\n" +msgstr "" +"\n" +"Reporte errores a <%s>.\n" + +#: pg_amcheck.c:1211 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "Sitio web de %s: <%s>\n" + +#: pg_amcheck.c:1269 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "%*s/%s relaciones (%d%%), %*s/%s páginas (%d%%) %*s" + +#: pg_amcheck.c:1280 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "%*s/%s relaciones (%d%%), %*s/%s páginas (%d%%), (%s%-*.*s)" + +#: pg_amcheck.c:1295 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "%*s/%s relaciones (%d%%), %*s/%s páginas (%d%%)" + +#: pg_amcheck.c:1354 pg_amcheck.c:1387 +#, c-format +msgid "improper qualified name (too many dotted names): %s" +msgstr "el nombre no es válido (demasiados puntos): %s" + +#: pg_amcheck.c:1432 +#, c-format +msgid "improper relation name (too many dotted names): %s" +msgstr "el nombre de relación no es válido (demasiados puntos): %s" + +#: pg_amcheck.c:1585 pg_amcheck.c:1727 +#, c-format +msgid "including database \"%s\"" +msgstr "incluyendo base de datos «%s»" + +#: pg_amcheck.c:1707 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "error interno: se recibió pattern_id de base de datos inesperado (%d)" + +#: pg_amcheck.c:1711 +#, c-format +msgid "no connectable databases to check matching \"%s\"" +msgstr "no hay bases de datos a las que se pueda conectar que coincidan con «%s»" + +#: pg_amcheck.c:2170 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "error interno: se recibió pattern_id de relación inesperado (%d)" diff --git a/src/bin/pg_amcheck/po/fr.po b/src/bin/pg_amcheck/po/fr.po new file mode 100644 index 0000000..04731bd --- /dev/null +++ b/src/bin/pg_amcheck/po/fr.po @@ -0,0 +1,575 @@ +# LANGUAGE message translation file for pg_amcheck +# Copyright (C) 2021 PostgreSQL Global Development Group +# This file is distributed under the same license as the pg_amcheck (PostgreSQL) package. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: pg_amcheck (PostgreSQL) 14\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2022-05-03 03:04+0000\n" +"PO-Revision-Date: 2021-08-31 17:05+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.0\n" + +#: ../../../src/common/logging.c:259 +#, c-format +msgid "fatal: " +msgstr "fatal : " + +#: ../../../src/common/logging.c:266 +#, c-format +msgid "error: " +msgstr "erreur : " + +#: ../../../src/common/logging.c:273 +#, c-format +msgid "warning: " +msgstr "attention : " + +#: ../../fe_utils/cancel.c:189 ../../fe_utils/cancel.c:238 +msgid "Cancel request sent\n" +msgstr "Requête d'annulation envoyée\n" + +#: ../../fe_utils/cancel.c:190 ../../fe_utils/cancel.c:239 +msgid "Could not send cancel request: " +msgstr "N'a pas pu envoyer la requête d'annulation : " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "n'a pas pu se connecter à la base de données %s : plus de mémoire" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1678 pg_amcheck.c:2126 +#, c-format +msgid "query failed: %s" +msgstr "échec de la requête : %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:598 pg_amcheck.c:1128 pg_amcheck.c:1679 pg_amcheck.c:2127 +#, c-format +msgid "query was: %s" +msgstr "la requête était : %s" + +#: pg_amcheck.c:330 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "le nombre maximum de jobs en parallèle doit être au moins de 1" + +#: pg_amcheck.c:402 +#, c-format +msgid "invalid argument for option %s" +msgstr "argument invalide pour l'option %s" + +#: pg_amcheck.c:411 +#, c-format +msgid "invalid start block" +msgstr "bloc de début invalide" + +#: pg_amcheck.c:416 +#, c-format +msgid "start block out of bounds" +msgstr "bloc de début hors des limites" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "bloc de fin invalide" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "bloc de fin hors des limites" + +#: pg_amcheck.c:456 pg_amcheck.c:482 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "Essayez « %s --help » pour plus d'informations.\n" + +#: pg_amcheck.c:464 +#, c-format +msgid "end block precedes start block" +msgstr "le bloc de fin précède le bloc de début" + +#: pg_amcheck.c:480 +#, c-format +msgid "too many command-line arguments (first is \"%s\")" +msgstr "trop d'arguments en ligne de commande (le premier étant « %s »)" + +#: pg_amcheck.c:501 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "ne peut pas spécifier un nom de base de données avec --all" + +#: pg_amcheck.c:510 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "ne peut pas spécifier à la fois le nom d'une base de données et des motifs de noms de base" + +#: pg_amcheck.c:540 +#, c-format +msgid "no databases to check" +msgstr "aucune base de données à vérifier" + +#: pg_amcheck.c:596 +#, c-format +msgid "database \"%s\": %s" +msgstr "base de données « %s » : %s" + +#: pg_amcheck.c:607 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "ignore la base « %s » : amcheck n'est pas installé" + +#: pg_amcheck.c:615 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "dans la base de données « %s » : utilisation de la version « %s » d'amcheck dans le schéma « %s »" + +#: pg_amcheck.c:637 +#, c-format +msgid "no heap tables to check matching \"%s\"" +msgstr "aucune table heap à vérifier correspondant à « %s »" + +#: pg_amcheck.c:640 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "aucun index btree à vérifier correspondant à « %s »" + +#: pg_amcheck.c:643 +#, c-format +msgid "no relations to check in schemas matching \"%s\"" +msgstr "aucune relation à vérifier dans les schémas correspondant à « %s »" + +#: pg_amcheck.c:646 +#, c-format +msgid "no relations to check matching \"%s\"" +msgstr "aucune relation à vérifier correspondant à « %s »" + +#: pg_amcheck.c:674 +#, c-format +msgid "no relations to check" +msgstr "aucune relation à vérifier" + +#: pg_amcheck.c:758 +#, c-format +msgid "checking heap table \"%s.%s.%s\"" +msgstr "vérification de la table heap « %s %s.%s »" + +#: pg_amcheck.c:774 +#, c-format +msgid "checking btree index \"%s.%s.%s\"" +msgstr "vérification de l'index btree « %s %s.%s »" + +#: pg_amcheck.c:921 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "erreur de l'envoi d'une commande à la base de données « %s » : %s" + +#: pg_amcheck.c:924 +#, c-format +msgid "command was: %s" +msgstr "la commande était : %s" + +#: pg_amcheck.c:1041 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "table heap « %s.%s.%s », bloc %s, décalage %s, attribut %s :\n" + +#: pg_amcheck.c:1048 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "table heap « %s.%s.%s », bloc %s, décalage %s :\n" + +#: pg_amcheck.c:1054 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "table heap « %s %s.%s », bloc %s :\n" + +#: pg_amcheck.c:1059 pg_amcheck.c:1070 +#, c-format +msgid "heap table \"%s.%s.%s\":\n" +msgstr "table heap « %s %s.%s » :\n" + +#: pg_amcheck.c:1074 pg_amcheck.c:1143 +#, c-format +msgid "query was: %s\n" +msgstr "la requête était : %s\n" + +#: pg_amcheck.c:1125 +#, c-format +msgid "btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d" +msgstr "index btree « %s.%s.%s » : la fonction de vérification des index btree a renvoyé un nombre de lignes inattendu : %d" + +#: pg_amcheck.c:1129 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "est-ce que les versions de %s et d'amcheck sont compatibles ?" + +#: pg_amcheck.c:1139 +#, c-format +msgid "btree index \"%s.%s.%s\":\n" +msgstr "vérification de l'index btree« %s %s.%s » :\n" + +#: pg_amcheck.c:1164 +#, c-format +msgid "" +"%s checks objects in a PostgreSQL database for corruption.\n" +"\n" +msgstr "" +"%s utilise le module amcheck pour vérifier si les objets d' une base\n" +"PostgreSQL sont corrompus.\n" +"\n" + +#: pg_amcheck.c:1165 +#, c-format +msgid "Usage:\n" +msgstr "Usage :\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [OPTION]... [BASE]\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid "" +"\n" +"Target options:\n" +msgstr "" +"\n" +"Options de la cible :\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all vérifie toutes les bases\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr " -d, --database=MOTIF vérifie les bases correspondantes\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr " -D, --exclude-database=MOTIF ne vérifie PAS les bases correspondantes\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr " -i, --index=MOTIF vérifie les index correspondants\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr " -I, --exclude-index=MOTIF ne vérifie PAS les index correspondants\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr " -r, --relation=MOTIF vérifie les relations correspondantes\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr " -R, --exclude-relation=MOTIF ne vérifie PAS les relations correspondantes\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr " -s, --schema=MOTIF vérifie les schémas correspondants\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr " -S, --exclude-schema=MOTIF ne vérifie PAS les schémas correspondants\n" + +#: pg_amcheck.c:1177 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr " -t, --table=MOTIF vérifie les tables correspondantes\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr " -T, --exclude-table=MOTIF ne vérifie PAS les tables correspondantes\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid " --no-dependent-indexes do NOT expand list of relations to include indexes\n" +msgstr "" +" --no-dependent-indexes n'étend PAS la liste des relations pour inclure\n" +" les index\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid " --no-dependent-toast do NOT expand list of relations to include TOAST tables\n" +msgstr "" +" --no-dependent-toast n'étend PAS la liste des relations pour inclure\n" +" les TOAST\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid " --no-strict-names do NOT require patterns to match objects\n" +msgstr "" +" --no-strict-names ne requiert PAS que les motifs correspondent à\n" +" des objets\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid "" +"\n" +"Table checking options:\n" +msgstr "" +"\n" +"Options de vérification des tables :\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid " --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr " --exclude-toast-pointers ne suit PAS les pointeurs de TOAST\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid " --on-error-stop stop checking at end of first corrupt page\n" +msgstr "" +" --on-error-stop arrête la vérification à la fin du premier bloc\n" +" corrompu\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid " --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n" +msgstr "" +" --skip=OPTION ne vérifie PAS les blocs « all-frozen » et\n" +" « all-visible »\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid " --startblock=BLOCK begin checking table(s) at the given block number\n" +msgstr "" +" --startblock=BLOC commence la vérification des tables au numéro\n" +" de bloc indiqué\n" + +#: pg_amcheck.c:1187 +#, c-format +msgid " --endblock=BLOCK check table(s) only up to the given block number\n" +msgstr "" +" --endblock=BLOC vérifie les tables jusqu'au numéro de bloc\n" +" indiqué\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid "" +"\n" +"B-tree index checking options:\n" +msgstr "" +"\n" +"Options de vérification des index Btree :\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid " --heapallindexed check that all heap tuples are found within indexes\n" +msgstr "" +" --heapallindexed vérifie que tous les enregistrements de la\n" +" table sont référencés dans les index\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid " --parent-check check index parent/child relationships\n" +msgstr "" +" --parent-check vérifie les relations parent/enfants dans les\n" +" index\n" + +#: pg_amcheck.c:1191 +#, c-format +msgid " --rootdescend search from root page to refind tuples\n" +msgstr "" +" --rootdescend recherche à partir de la racine pour trouver\n" +" les lignes\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid "" +"\n" +"Connection options:\n" +msgstr "" +"\n" +"Options de connexion :\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid " -h, --host=HOSTNAME database server host or socket directory\n" +msgstr " -h, --host=HÔTE IP/alias du serveur ou répertoire du socket\n" + +#: pg_amcheck.c:1194 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=PORT port du serveur de bases de données\n" + +#: pg_amcheck.c:1195 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr " -U, --username=UTILISATEUR nom d'utilisateur pour la connexion\n" + +#: pg_amcheck.c:1196 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password ne demande jamais un mot de passe\n" + +#: pg_amcheck.c:1197 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password force la saisie d'un mot de passe\n" + +#: pg_amcheck.c:1198 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=BASE change la base de maintenance\n" + +#: pg_amcheck.c:1199 +#, c-format +msgid "" +"\n" +"Other options:\n" +msgstr "" +"\n" +"Autres options :\n" + +#: pg_amcheck.c:1200 +#, c-format +msgid " -e, --echo show the commands being sent to the server\n" +msgstr " -e, --echo affiche les commandes envoyées au serveur\n" + +#: pg_amcheck.c:1201 +#, c-format +msgid " -j, --jobs=NUM use this many concurrent connections to the server\n" +msgstr "" +" -j, --jobs=NOMBRE utilise ce nombre de connexions simultanées au\n" +" serveur\n" + +#: pg_amcheck.c:1202 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress affiche la progression\n" + +#: pg_amcheck.c:1203 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose mode verbeux\n" + +#: pg_amcheck.c:1204 +#, c-format +msgid " -V, --version output version information, then exit\n" +msgstr " -V, --version affiche la version puis quitte\n" + +#: pg_amcheck.c:1205 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing installe les extensions manquantes\n" + +#: pg_amcheck.c:1206 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help affiche cette aide puis quitte\n" + +#: pg_amcheck.c:1208 +#, c-format +msgid "" +"\n" +"Report bugs to <%s>.\n" +msgstr "" +"\n" +"Rapporter les bogues à <%s>.\n" + +#: pg_amcheck.c:1209 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "Page d'accueil de %s : <%s>\n" + +#: pg_amcheck.c:1267 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "relations %*s/%s (%d%%), blocs %*s/%s (%d%%) %*s" + +#: pg_amcheck.c:1278 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "relations %*s/%s (%d%%), blocs %*s/%s (%d%%) (%s%-*.*s)" + +#: pg_amcheck.c:1293 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "relations %*s/%s (%d%%), blocs %*s/%s (%d%%)" + +#: pg_amcheck.c:1352 pg_amcheck.c:1385 +#, c-format +msgid "improper qualified name (too many dotted names): %s" +msgstr "mauvaise qualification du nom (trop de points entre les noms) : %s" + +#: pg_amcheck.c:1430 +#, c-format +msgid "improper relation name (too many dotted names): %s" +msgstr "nom de relation incorrecte (trop de points entre les noms) : %s" + +#: pg_amcheck.c:1583 pg_amcheck.c:1725 +#, c-format +msgid "including database \"%s\"" +msgstr "en incluant la base de données : « %s »" + +#: pg_amcheck.c:1705 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "erreur interne : a reçu un pattern_id %d inattendu de la base" + +#: pg_amcheck.c:1709 +#, c-format +msgid "no connectable databases to check matching \"%s\"" +msgstr "aucune base de données connectable à vérifier correspondant à « %s »" + +#: pg_amcheck.c:2168 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "erreur interne : a reçu un pattern_id %d inattendu de la relation" + +#~ msgid "" +#~ "\n" +#~ "Other Options:\n" +#~ msgstr "" +#~ "\n" +#~ "Autres options:\n" + +#~ msgid " -?, --help show this help, then exit\n" +#~ msgstr " -?, --help affiche cette aide, puis quitte\n" + +#~ msgid " -V, --version output version information, then exit\n" +#~ msgstr " -V, --version affiche la version, puis quitte\n" + +#~ msgid " -e, --echo show the commands being sent to the server\n" +#~ msgstr " -e, --echo affiche les commandes envoyées au serveur\n" + +#~ msgid " -q, --quiet don't write any messages\n" +#~ msgstr " -q, --quiet n'écrit aucun message\n" + +#~ msgid " -q, --quiet don't write any messages\n" +#~ msgstr " -q, --quiet n'écrit aucun message\n" + +#~ msgid " -v, --verbose write a lot of output\n" +#~ msgstr " -v, --verbose mode verbeux\n" + +#~ msgid "invalid skip option" +#~ msgstr "option skip invalide" + +#~ msgid "number of parallel jobs must be at least 1\n" +#~ msgstr "le nombre de jobs parallèles doit être au moins de 1\n" diff --git a/src/bin/pg_amcheck/po/ja.po b/src/bin/pg_amcheck/po/ja.po new file mode 100644 index 0000000..84a9fb0 --- /dev/null +++ b/src/bin/pg_amcheck/po/ja.po @@ -0,0 +1,527 @@ +# LANGUAGE message translation file for pg_amcheck +# Copyright (C) 2022 PostgreSQL Global Development Group +# This file is distributed under the same license as the pg_amcheck (PostgreSQL) package. +# Kyotaro Horiguchi <horikyota.ntt@gmail.com>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: pg_amcheck (PostgreSQL 14)\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2021-08-25 17:21+0900\n" +"PO-Revision-Date: 2021-08-25 11:19+0900\n" +"Last-Translator: \n" +"Language-Team: \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" + +#: ../../../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 "警告: " + +#: ../../fe_utils/cancel.c:161 ../../fe_utils/cancel.c:206 +msgid "Cancel request sent\n" +msgstr "キャンセル要求を送信しました\n" + +#: ../../fe_utils/cancel.c:165 ../../fe_utils/cancel.c:210 +msgid "Could not send cancel request: " +msgstr "キャンセル要求を送信できませんでした: " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "データベース%sに接続できませんでした: メモリ不足" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1641 pg_amcheck.c:2080 +#, c-format +msgid "query failed: %s" +msgstr "問い合わせが失敗しました: %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:598 pg_amcheck.c:1112 pg_amcheck.c:1642 pg_amcheck.c:2081 +#, c-format +msgid "query was: %s" +msgstr "問い合わせ: %s" + +#: pg_amcheck.c:330 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "並列ジョブの数は最低でも1以上でなければなりません" + +#: pg_amcheck.c:402 +#, c-format +msgid "invalid argument for option %s" +msgstr "オプション%sの引数が不正です" + +#: pg_amcheck.c:411 +#, c-format +msgid "invalid start block" +msgstr "不正な開始ブロック" + +#: pg_amcheck.c:416 +#, c-format +msgid "start block out of bounds" +msgstr "開始ブロックが範囲外" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "不正な終了ブロック" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "終了ブロックが範囲外" + +#: pg_amcheck.c:456 pg_amcheck.c:482 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "詳細は\"%s --help\"で確認してください。\n" + +#: pg_amcheck.c:464 +#, c-format +msgid "end block precedes start block" +msgstr "終了ブロックが開始ブロックの前にあります" + +#: pg_amcheck.c:480 +#, c-format +msgid "too many command-line arguments (first is \"%s\")" +msgstr "コマンドライン引数が多すぎます (先頭は\"%s\")" + +#: pg_amcheck.c:501 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "データベース名を -all と同時に指定することはできません" + +#: pg_amcheck.c:510 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "データベース名とデータベースパターンは同時に指定できません" + +#: pg_amcheck.c:540 +#, c-format +msgid "no databases to check" +msgstr "検査すべきデータベースがありません" + +#: pg_amcheck.c:596 +#, c-format +msgid "database \"%s\": %s" +msgstr "データベース\"%s\": %s" + +#: pg_amcheck.c:607 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "データベース\"%s\"をスキップします: amcheckがインストールされていません" + +#: pg_amcheck.c:615 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "データベース\"%1$s\": スキーマ%3$sのamcheckバージョン\"%2$s\"を使用" + +#: pg_amcheck.c:637 +#, c-format +msgid "no heap tables to check matching \"%s\"" +msgstr "\"%s\"に合致する検査すべきヒープテーブルがありません" + +#: pg_amcheck.c:640 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "\"%s\"に合致する検査すべきbtreeインデックスがありません" + +#: pg_amcheck.c:643 +#, c-format +msgid "no relations to check in schemas matching \"%s\"" +msgstr "\"%s\"に合致するスキーマに検査すべきリレーションがありません" + +#: pg_amcheck.c:646 +#, c-format +msgid "no relations to check matching \"%s\"" +msgstr "\"%s\"に合致する検査すべきリレーションがありません" + +#: pg_amcheck.c:674 +#, c-format +msgid "no relations to check" +msgstr "検査すべきリレーションがありません" + +#: pg_amcheck.c:758 +#, c-format +msgid "checking heap table \"%s.%s.%s\"" +msgstr "ヒープテーブル\"%s.%s.%s\"の検査中" + +#: pg_amcheck.c:774 +#, c-format +msgid "checking btree index \"%s.%s.%s\"" +msgstr "btreeインデックス\"%s.%s.%s\"の検査中" + +#: pg_amcheck.c:907 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "データベース\"%s\"へのコマンド送出中のエラー: %s" + +#: pg_amcheck.c:910 +#, c-format +msgid "command was: %s" +msgstr "コマンド: %s" + +#: pg_amcheck.c:1027 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "ヒープテーブル\"%s.%s.%s\"、ブロック%s、オフセット%s、属性%s:\n" + +#: pg_amcheck.c:1034 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "ヒープテーブル\"%s.%s.%s\"、ブロック%s、オフセット%s:\n" + +#: pg_amcheck.c:1040 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "ヒープテーブル\"%s.%s.%s\"、ブロック%sの検査中\n" + +#: pg_amcheck.c:1045 pg_amcheck.c:1056 +#, c-format +msgid "heap table \"%s.%s.%s\":\n" +msgstr "ヒープテーブル\"%s.%s.%s\"の検査中\n" + +#: pg_amcheck.c:1060 pg_amcheck.c:1127 +#, c-format +msgid "query was: %s\n" +msgstr "問い合わせ: %s\n" + +#: pg_amcheck.c:1109 +#, c-format +msgid "btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d" +msgstr "btreeインデックス\"%s.%s.%s\": btree検査関数が予期しない数の行を返却しました: %d" + +#: pg_amcheck.c:1113 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "%sとamcheckのバージョンは合っていますか?" + +#: pg_amcheck.c:1123 +#, c-format +msgid "btree index \"%s.%s.%s\":\n" +msgstr "btreeインデックス\"%s.%s.%s\"の検査中\n" + +#: pg_amcheck.c:1148 +#, c-format +msgid "" +"%s checks objects in a PostgreSQL database for corruption.\n" +"\n" +msgstr "" +"%sはPostgreSQLデータベース内のオブジェクトの破損の検査を行います。\n" +"\n" + +#: pg_amcheck.c:1149 +#, c-format +msgid "Usage:\n" +msgstr "使用方法:\n" + +#: pg_amcheck.c:1150 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [オプション]... [データベース名]\n" + +#: pg_amcheck.c:1151 +#, c-format +msgid "" +"\n" +"Target options:\n" +msgstr "" +"\n" +"対象指定オプション:\n" + +#: pg_amcheck.c:1152 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all すべてのデータベースを検査する\n" + +#: pg_amcheck.c:1153 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr " -d, --database=PATTERN 合致するデータベースを検査する\n" + +#: pg_amcheck.c:1154 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr " -D, --exclude-database=PATTERN 合致するデータベースを検査「しない」\n" + +#: pg_amcheck.c:1155 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr " -i, --index=PATTERN 合致するインデックスを検査する\n" + +#: pg_amcheck.c:1156 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr " -I, --exclude-index=PATTERN 合致するインデックスを検査「しない」\n" + +#: pg_amcheck.c:1157 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr " -r, --relation=PATTERN 合致するリレーションを検査する\n" + +#: pg_amcheck.c:1158 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr " -R, --exclude-relation=PATTERN 合致するリレーションを検査「しない」\n" + +#: pg_amcheck.c:1159 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr " -s, --schema=PATTERN 合致するスキーマを検査する\n" + +#: pg_amcheck.c:1160 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr " -S, --exclude-schema=PATTERN 合致するスキーマを検査「しない」\n" + +#: pg_amcheck.c:1161 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr " -t, --table=PATTERN 合致するテーブルを検査する\n" + +#: pg_amcheck.c:1162 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr " -T, --exclude-table=PATTERN 合致するテーブルを検査「しない」\n" + +#: pg_amcheck.c:1163 +#, c-format +msgid " --no-dependent-indexes do NOT expand list of relations to include indexes\n" +msgstr "" +" --no-dependent-indexes リレーションのリストをインデックスを含むように\n" +" 拡張「しない」\n" + +#: pg_amcheck.c:1164 +#, c-format +msgid " --no-dependent-toast do NOT expand list of relations to include TOAST tables\n" +msgstr "" +" --no-dependent-toast リレーションのリストをTOASTテーブルを含むよう\n" +" に拡張「しない」\n" + +#: pg_amcheck.c:1165 +#, c-format +msgid " --no-strict-names do NOT require patterns to match objects\n" +msgstr "" +" --no-strict-names パターンにオブジェクトが合致しないことを許容\n" +" する\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid "" +"\n" +"Table checking options:\n" +msgstr "" +"\n" +"テーブル検査オプション:\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid " --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr " --exclude-toast-pointers リレーションTOASTポインタを追跡「しない」\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " --on-error-stop stop checking at end of first corrupt page\n" +msgstr " --on-error-stop 検査を最初の破壊ページで停止する\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid " --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n" +msgstr "" +" --skip=OPTION \"all-frozen\"あるいは\"all-visible\"である\n" +" ブロックを検査「しない」\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid " --startblock=BLOCK begin checking table(s) at the given block number\n" +msgstr "" +" --startblock=BLOCK テーブルの検索を指定したブロック番号から開始\n" +" する\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " --endblock=BLOCK check table(s) only up to the given block number\n" +msgstr "" +" --endblock=BLOCK テーブルの検索を指定したブロック番号までで停止\n" +" する\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid "" +"\n" +"B-tree index checking options:\n" +msgstr "" +"\n" +"B-treeインデックス検査オプション:\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " --heapallindexed check that all heap tuples are found within indexes\n" +msgstr "" +" --heapallindexed すべてのヒープタプルがインデックス中に見つか\n" +" ることを検証する\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " --parent-check check index parent/child relationships\n" +msgstr " --parent-check インデックスの親子関係を検査する\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " --rootdescend search from root page to refind tuples\n" +msgstr " --rootdescend タプルの再探索をルートページから行う\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid "" +"\n" +"Connection options:\n" +msgstr "" +"\n" +"接続オプション:\n" + +#: pg_amcheck.c:1177 +#, c-format +msgid " -h, --host=HOSTNAME database server host or socket directory\n" +msgstr "" +" -h, --host=HOSTNAME データベースサーバーのホストまたはソケット\n" +" ディレクトリ\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=PORT データベースサーバーのポート\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr " -U, --username=USERNAME 接続に用いるユーザー名\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password パスワードを要求しない\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password パスワード要求を強制する\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=DBNAME 代替の保守データベース\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid "" +"\n" +"Other options:\n" +msgstr "" +"\n" +"その他のオプション:\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid " -e, --echo show the commands being sent to the server\n" +msgstr " -e, --echo サーバーに送られるコマンドを表示\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid " -j, --jobs=NUM use this many concurrent connections to the server\n" +msgstr " -j, --jobs=NUM 使用するサーバー接続数を指定する\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress 進捗状況を表示する\n" + +#: pg_amcheck.c:1187 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose 多くのメッセージを出力します\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid " -V, --version output version information, then exit\n" +msgstr " -V, --version バージョン情報を表示して終了\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing 足りない機能拡張をインストールする\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help このヘルプを表示して終了\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid "" +"\n" +"Report bugs to <%s>.\n" +msgstr "" +"\n" +"バグは<%s>に報告してください。\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "%s ホームページ: <%s>\n" + +#: pg_amcheck.c:1251 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "%*s/%s リレーション (%d%%)、 %*s/%s ページ (%d%%) %*s" + +#: pg_amcheck.c:1262 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "%*s/%s リレーション (%d%%)、 %*s/%s ページ (%d%%), (%s%-*.*s)" + +#: pg_amcheck.c:1277 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "%*s/%s リレーション (%d%%)、 %*s/%s ページ (%d%%)" + +#: pg_amcheck.c:1546 pg_amcheck.c:1688 +#, c-format +msgid "including database \"%s\"" +msgstr "データベース\"%s\"を含めます" + +#: pg_amcheck.c:1668 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "内部エラー: 予期しないデータベースパターンID%dを受信しました" + +#: pg_amcheck.c:1672 +#, c-format +msgid "no connectable databases to check matching \"%s\"" +msgstr "\"%s”に合致する検査すべき接続可能なデータベースがありません" + +#: pg_amcheck.c:2122 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "内部エラー: 予期しないリレーションパターンID%dを受信しました" diff --git a/src/bin/pg_amcheck/po/ru.po b/src/bin/pg_amcheck/po/ru.po new file mode 100644 index 0000000..ec5b01d --- /dev/null +++ b/src/bin/pg_amcheck/po/ru.po @@ -0,0 +1,591 @@ +# Alexander Lakhin <a.lakhin@postgrespro.ru>, 2021, 2022. +msgid "" +msgstr "" +"Project-Id-Version: pg_amcheck (PostgreSQL) 14\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2022-05-07 06:06+0300\n" +"PO-Revision-Date: 2022-05-07 06:16+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" + +#: ../../../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 "предупреждение: " + +#: ../../fe_utils/cancel.c:189 ../../fe_utils/cancel.c:238 +msgid "Cancel request sent\n" +msgstr "Сигнал отмены отправлен\n" + +#: ../../fe_utils/cancel.c:190 ../../fe_utils/cancel.c:239 +msgid "Could not send cancel request: " +msgstr "Отправить сигнал отмены не удалось: " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "не удалось подключиться к базе %s (нехватка памяти)" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1678 pg_amcheck.c:2126 +#, c-format +msgid "query failed: %s" +msgstr "ошибка при выполнении запроса: %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:598 pg_amcheck.c:1128 pg_amcheck.c:1679 pg_amcheck.c:2127 +#, c-format +msgid "query was: %s" +msgstr "запрос: %s" + +#: pg_amcheck.c:330 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "число параллельных заданий должно быть не меньше 1" + +#: pg_amcheck.c:402 +#, c-format +msgid "invalid argument for option %s" +msgstr "недопустимый аргумент параметра %s" + +#: pg_amcheck.c:411 +#, c-format +msgid "invalid start block" +msgstr "неверный начальный блок" + +#: pg_amcheck.c:416 +#, c-format +msgid "start block out of bounds" +msgstr "начальный блок вне допустимых пределов" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "неверный конечный блок" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "конечный блок вне допустимых пределов" + +#: pg_amcheck.c:456 pg_amcheck.c:482 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "Для дополнительной информации попробуйте \"%s --help\".\n" + +#: pg_amcheck.c:464 +#, c-format +msgid "end block precedes start block" +msgstr "конечный блок предшествует начальному" + +#: pg_amcheck.c:480 +#, c-format +msgid "too many command-line arguments (first is \"%s\")" +msgstr "слишком много аргументов командной строки (первый: \"%s\")" + +#: pg_amcheck.c:501 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "имя базы данных нельзя задавать с --all" + +#: pg_amcheck.c:510 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "нельзя задавать одновременно имя базы данных и шаблоны имён" + +#: pg_amcheck.c:540 +#, c-format +msgid "no databases to check" +msgstr "не указаны базы для проверки" + +#: pg_amcheck.c:596 +#, c-format +msgid "database \"%s\": %s" +msgstr "база данных \"%s\": %s" + +#: pg_amcheck.c:607 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "база \"%s\" пропускается: расширение amcheck не установлено" + +#: pg_amcheck.c:615 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "база \"%s\": используется amcheck версии \"%s\" в схеме \"%s\"" + +#: pg_amcheck.c:637 +#, c-format +msgid "no heap tables to check matching \"%s\"" +msgstr "не найдены подлежащие проверке базовые таблицы, соответствующие \"%s\"" + +#: pg_amcheck.c:640 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "не найдены подлежащие проверке индексы btree, соответствующие \"%s\"" + +#: pg_amcheck.c:643 +#, c-format +msgid "no relations to check in schemas matching \"%s\"" +msgstr "" +"не найдены подлежащие проверке отношения в схемах, соответствующих \"%s\"" + +#: pg_amcheck.c:646 +#, c-format +msgid "no relations to check matching \"%s\"" +msgstr "не найдены подлежащие проверке отношения, соответствующие \"%s\"" + +#: pg_amcheck.c:674 +#, c-format +msgid "no relations to check" +msgstr "не найдены отношения для проверки" + +#: pg_amcheck.c:758 +#, c-format +msgid "checking heap table \"%s.%s.%s\"" +msgstr "проверка базовой таблицы \"%s.%s.%s\"" + +#: pg_amcheck.c:774 +#, c-format +msgid "checking btree index \"%s.%s.%s\"" +msgstr "проверка индекса btree \"%s.%s.%s\"" + +#: pg_amcheck.c:921 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "ошибка передачи команды базе \"%s\": %s" + +#: pg_amcheck.c:924 +#, c-format +msgid "command was: %s" +msgstr "команда: %s" + +#: pg_amcheck.c:1041 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "базовая таблица \"%s.%s.%s\", блок %s, смещение %s, атрибут %s:\n" + +#: pg_amcheck.c:1048 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "базовая таблица \"%s.%s.%s\", блок %s, смещение %s:\n" + +#: pg_amcheck.c:1054 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "базовая таблица \"%s.%s.%s\", блок %s:\n" + +#: pg_amcheck.c:1059 pg_amcheck.c:1070 +#, c-format +msgid "heap table \"%s.%s.%s\":\n" +msgstr "базовая таблица \"%s.%s.%s\":\n" + +#: pg_amcheck.c:1074 pg_amcheck.c:1143 +#, c-format +msgid "query was: %s\n" +msgstr "запрос: %s\n" + +#: pg_amcheck.c:1125 +#, c-format +msgid "" +"btree index \"%s.%s.%s\": btree checking function returned unexpected number " +"of rows: %d" +msgstr "" +"индекс btree \"%s.%s.%s\": функция проверки btree выдала неожиданное " +"количество строк: %d" + +#: pg_amcheck.c:1129 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "Совместимы ли версии %s и amcheck?" + +#: pg_amcheck.c:1139 +#, c-format +msgid "btree index \"%s.%s.%s\":\n" +msgstr "индекс btree \"%s.%s.%s\":\n" + +#: pg_amcheck.c:1164 +#, c-format +msgid "" +"%s checks objects in a PostgreSQL database for corruption.\n" +"\n" +msgstr "" +"%s проверяет объекты в базе данных PostgreSQL на предмет повреждений.\n" +"\n" + +#: pg_amcheck.c:1165 +#, c-format +msgid "Usage:\n" +msgstr "Использование:\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [ПАРАМЕТР]... [ИМЯ_БД]\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid "" +"\n" +"Target options:\n" +msgstr "" +"\n" +"Параметры выбора объектов:\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all проверить все базы\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr "" +" -d, --database=ШАБЛОН проверить соответствующие шаблону базы\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr "" +" -D, --exclude-database=ШАБЛОН не проверять соответствующие шаблону базы\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr "" +" -i, --index=ШАБЛОН проверить соответствующие шаблону индексы\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr "" +" -I, --exclude-index=ШАБЛОН не проверять соответствующие шаблону " +"индексы\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr "" +" -r, --relation=ШАБЛОН проверить соответствующие шаблону " +"отношения\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr "" +" -R, --exclude-relation=ШАБЛОН не проверять соответствующие шаблону " +"отношения\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr "" +" -s, --schema=ШАБЛОН проверить соответствующие шаблону схемы\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr "" +" -S, --exclude-schema=ШАБЛОН не проверять соответствующие шаблону " +"схемы\n" + +#: pg_amcheck.c:1177 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr "" +" -t, --table=ШАБЛОН проверить соответствующие шаблону таблицы\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr "" +" -T, --exclude-table=ШАБЛОН не проверять соответствующие шаблону " +"таблицы\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid "" +" --no-dependent-indexes do NOT expand list of relations to include " +"indexes\n" +msgstr "" +" --no-dependent-indexes не включать в список проверяемых отношений " +"индексы\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid "" +" --no-dependent-toast do NOT expand list of relations to include " +"TOAST tables\n" +msgstr "" +" --no-dependent-toast не включать в список проверяемых отношений " +"TOAST-таблицы\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid "" +" --no-strict-names do NOT require patterns to match objects\n" +msgstr "" +" --no-strict-names не требовать наличия объектов, " +"соответствующих шаблонам\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid "" +"\n" +"Table checking options:\n" +msgstr "" +"\n" +"Параметры проверки таблиц:\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid "" +" --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr "" +" --exclude-toast-pointers не переходить по указателям в TOAST\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid "" +" --on-error-stop stop checking at end of first corrupt " +"page\n" +msgstr "" +" --on-error-stop прекратить проверку по достижении конца " +"первой повреждённой страницы\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid "" +" --skip=OPTION do NOT check \"all-frozen\" or \"all-" +"visible\" blocks\n" +msgstr "" +" --skip=ТИП_БЛОКА не проверять блоки типа \"all-frozen\" или " +"\"all-visible\"\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid "" +" --startblock=BLOCK begin checking table(s) at the given block " +"number\n" +msgstr "" +" --startblock=БЛОК начать проверку таблиц(ы) с блока с " +"заданным номером\n" + +# skip-rule: no-space-before-parentheses +#: pg_amcheck.c:1187 +#, c-format +msgid "" +" --endblock=BLOCK check table(s) only up to the given block " +"number\n" +msgstr "" +" --endblock=БЛОК проверить таблицы(у) до блока с заданным " +"номером\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid "" +"\n" +"B-tree index checking options:\n" +msgstr "" +"\n" +"Параметры проверки индексов-B-деревьев:\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid "" +" --heapallindexed check that all heap tuples are found " +"within indexes\n" +msgstr "" +" --heapallindexed проверить, что всем кортежам кучи " +"находится соответствие в индексах\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid "" +" --parent-check check index parent/child relationships\n" +msgstr "" +" --parent-check проверить связи родитель/потомок в " +"индексах\n" + +#: pg_amcheck.c:1191 +#, c-format +msgid "" +" --rootdescend search from root page to refind tuples\n" +msgstr "" +" --rootdescend перепроверять поиск кортежей от корневой " +"страницы\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid "" +"\n" +"Connection options:\n" +msgstr "" +"\n" +"Параметры подключения:\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid "" +" -h, --host=HOSTNAME database server host or socket directory\n" +msgstr "" +" -h, --host=ИМЯ имя сервера баз данных или каталог " +"сокетов\n" + +#: pg_amcheck.c:1194 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=ПОРТ порт сервера баз данных\n" + +#: pg_amcheck.c:1195 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr "" +" -U, --username=ИМЯ имя пользователя для подключения к " +"серверу\n" + +#: pg_amcheck.c:1196 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password не запрашивать пароль\n" + +#: pg_amcheck.c:1197 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password запросить пароль\n" + +#: pg_amcheck.c:1198 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=ИМЯ_БД другая опорная база данных\n" + +#: pg_amcheck.c:1199 +#, c-format +msgid "" +"\n" +"Other options:\n" +msgstr "" +"\n" +"Другие параметры:\n" + +#: pg_amcheck.c:1200 +#, c-format +msgid "" +" -e, --echo show the commands being sent to the " +"server\n" +msgstr "" +" -e, --echo отображать команды, отправляемые серверу\n" + +#: pg_amcheck.c:1201 +#, c-format +msgid "" +" -j, --jobs=NUM use this many concurrent connections to " +"the server\n" +msgstr "" +" -j, --jobs=ЧИСЛО устанавливать заданное число подключений к " +"серверу\n" + +#: pg_amcheck.c:1202 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress показывать прогресс операции\n" + +#: pg_amcheck.c:1203 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose выводить исчерпывающие сообщения\n" + +#: pg_amcheck.c:1204 +#, c-format +msgid "" +" -V, --version output version information, then exit\n" +msgstr " -V, --version показать версию и выйти\n" + +#: pg_amcheck.c:1205 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing установить недостающие расширения\n" + +#: pg_amcheck.c:1206 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help показать эту справку и выйти\n" + +#: pg_amcheck.c:1208 +#, c-format +msgid "" +"\n" +"Report bugs to <%s>.\n" +msgstr "" +"\n" +"Об ошибках сообщайте по адресу <%s>.\n" + +#: pg_amcheck.c:1209 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "Домашняя страница %s: <%s>\n" + +#: pg_amcheck.c:1267 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "отношений: %*s/%s (%d%%), страниц: %*s/%s (%d%%) %*s" + +#: pg_amcheck.c:1278 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "отношений: %*s/%s (%d%%), страниц: %*s/%s (%d%%) (%s%-*.*s)" + +#: pg_amcheck.c:1293 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "отношений: %*s/%s (%d%%), страниц: %*s/%s (%d%%)" + +#: pg_amcheck.c:1352 pg_amcheck.c:1385 +#, c-format +msgid "improper qualified name (too many dotted names): %s" +msgstr "неверное полное имя (слишком много компонентов): %s" + +#: pg_amcheck.c:1430 +#, c-format +msgid "improper relation name (too many dotted names): %s" +msgstr "неверное имя отношения (слишком много компонентов): %s" + +#: pg_amcheck.c:1583 pg_amcheck.c:1725 +#, c-format +msgid "including database \"%s\"" +msgstr "выбирается база \"%s\"" + +#: pg_amcheck.c:1705 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "внутренняя ошибка: получен неожиданный идентификатор шаблона базы %d" + +#: pg_amcheck.c:1709 +#, c-format +msgid "no connectable databases to check matching \"%s\"" +msgstr "" +"не найдены подлежащие проверке доступные базы, соответствующие шаблону \"%s\"" + +#: pg_amcheck.c:2168 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "" +"внутренняя ошибка: получен неожиданный идентификатор шаблона отношения %d" diff --git a/src/bin/pg_amcheck/po/sv.po b/src/bin/pg_amcheck/po/sv.po new file mode 100644 index 0000000..407b26d --- /dev/null +++ b/src/bin/pg_amcheck/po/sv.po @@ -0,0 +1,520 @@ +# SWEDISH message translation file for pg_amcheck +# Copyright (C) 2021 PostgreSQL Global Development Group +# This file is distributed under the same license as the pg_amcheck (PostgreSQL) package. +# Dennis Björklund <db@zigo.dhs.org>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: pg_amcheck (PostgreSQL) 14\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2022-04-21 22:34+0000\n" +"PO-Revision-Date: 2021-11-07 06:41+0100\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" + +#: ../../../src/common/logging.c:259 +#, c-format +msgid "fatal: " +msgstr "fatalt: " + +#: ../../../src/common/logging.c:266 +#, c-format +msgid "error: " +msgstr "fel: " + +#: ../../../src/common/logging.c:273 +#, c-format +msgid "warning: " +msgstr "varning: " + +#: ../../fe_utils/cancel.c:189 ../../fe_utils/cancel.c:238 +msgid "Cancel request sent\n" +msgstr "Förfrågan om avbrytning skickad\n" + +#: ../../fe_utils/cancel.c:190 ../../fe_utils/cancel.c:239 +msgid "Could not send cancel request: " +msgstr "Kunde inte skicka förfrågan om avbrytning: " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "kunde inte ansluta till databas %s: slut på minne" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1678 pg_amcheck.c:2126 +#, c-format +msgid "query failed: %s" +msgstr "fråga misslyckades: %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:598 pg_amcheck.c:1128 pg_amcheck.c:1679 pg_amcheck.c:2127 +#, c-format +msgid "query was: %s" +msgstr "frågan var: %s" + +#: pg_amcheck.c:330 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "antalet parallella jobb måste vara minst 1" + +#: pg_amcheck.c:402 +#, c-format +msgid "invalid argument for option %s" +msgstr "ogiltigt argument för flaggan %s" + +#: pg_amcheck.c:411 +#, c-format +msgid "invalid start block" +msgstr "ogiltigt startblock" + +#: pg_amcheck.c:416 +#, c-format +msgid "start block out of bounds" +msgstr "startblocket utanför giltig gräns" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "ogiltigt slutblock" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "slutblocket utanför giltig gräns" + +#: pg_amcheck.c:456 pg_amcheck.c:482 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "Försök med \"%s --help\" för mer information.\n" + +#: pg_amcheck.c:464 +#, c-format +msgid "end block precedes start block" +msgstr "slutblocket kommer före startblocket" + +#: pg_amcheck.c:480 +#, c-format +msgid "too many command-line arguments (first is \"%s\")" +msgstr "för många kommandoradsargument (första är \"%s\")" + +#: pg_amcheck.c:501 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "kan inte ange databasnamn tillsammans med --all" + +#: pg_amcheck.c:510 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "kan inte ange både ett databasnamn och ett databasmönster" + +#: pg_amcheck.c:540 +#, c-format +msgid "no databases to check" +msgstr "inga databaser att kontrollera" + +#: pg_amcheck.c:596 +#, c-format +msgid "database \"%s\": %s" +msgstr "databas \"%s\": %s" + +#: pg_amcheck.c:607 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "hoppar över databas \"%s\": amcheck är inte installerad" + +#: pg_amcheck.c:615 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "i databas \"%s\": använder amcheck version \"%s\" i schema \"%s\"" + +#: pg_amcheck.c:637 +#, c-format +msgid "no heap tables to check matching \"%s\"" +msgstr "finns inga heap-tabeller för att kontrollera matchning \"%s\"" + +#: pg_amcheck.c:640 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "finns inga btree-index för att kontrollera matching \"%s\"" + +#: pg_amcheck.c:643 +#, c-format +msgid "no relations to check in schemas matching \"%s\"" +msgstr "finns inga relationer att kontrollera i schemamatchning \"%s\"" + +#: pg_amcheck.c:646 +#, c-format +msgid "no relations to check matching \"%s\"" +msgstr "finns inga relations för att kontrollera matching \"%s\"" + +#: pg_amcheck.c:674 +#, c-format +msgid "no relations to check" +msgstr "finns inga relationer att kontrollera" + +#: pg_amcheck.c:758 +#, c-format +msgid "checking heap table \"%s.%s.%s\"" +msgstr "kontrollerar heap-tabell \"%s.%s.%s\"" + +#: pg_amcheck.c:774 +#, c-format +msgid "checking btree index \"%s.%s.%s\"" +msgstr "kontrollerar btree-index \"%s.%s.%s\"" + +#: pg_amcheck.c:921 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "fel vid skickande av kommando till databas \"%s\": %s" + +#: pg_amcheck.c:924 +#, c-format +msgid "command was: %s" +msgstr "kommandot var: %s" + +#: pg_amcheck.c:1041 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "heap-tabell \"%s.%s.%s\", block %s, offset %s, attribut %s:\n" + +#: pg_amcheck.c:1048 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "heap-tabell \"%s.%s.%s\", block %s, offset %s:\n" + +#: pg_amcheck.c:1054 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "heap-tabell \"%s.%s.%s\", block %s:\n" + +#: pg_amcheck.c:1059 pg_amcheck.c:1070 +#, c-format +msgid "heap table \"%s.%s.%s\":\n" +msgstr "heap-tabell \"%s.%s.%s\":\n" + +#: pg_amcheck.c:1074 pg_amcheck.c:1143 +#, c-format +msgid "query was: %s\n" +msgstr "frågan var: %s\n" + +#: pg_amcheck.c:1125 +#, c-format +msgid "btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d" +msgstr "btree-index \"%s.%s.%s\": kontrollfunktion för btree returnerade oväntat antal rader: %d" + +#: pg_amcheck.c:1129 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "Är versionerna på %s och amcheck kompatibla?" + +#: pg_amcheck.c:1139 +#, c-format +msgid "btree index \"%s.%s.%s\":\n" +msgstr "btree-index \"%s.%s.%s\":\n" + +#: pg_amcheck.c:1164 +#, c-format +msgid "" +"%s checks objects in a PostgreSQL database for corruption.\n" +"\n" +msgstr "" +"%s kontrollerar objekt i en PostgreSQL-database för att hitta korruption.\n" +"\n" + +#: pg_amcheck.c:1165 +#, c-format +msgid "Usage:\n" +msgstr "Användning:\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [FLAGGA]... [DBNAMN]\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid "" +"\n" +"Target options:\n" +msgstr "" +"\n" +"Flaggor för destinationen:\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all kontrollera alla databaser\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr " -d, --database=MALL kontrollera matchande databas(er)\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr " -D, --exclude-database=MALL kontrollera INTE matchande databas(er)\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr " -i, --index=MALL kontrollera matchande index\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr " -I, --exclude-index=MALL kontrollera INTE matchande index\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr " -r, --relation=MALL kontrollera matchande relation(er)\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr " -R, --exclude-relation=MALL kontrollera INTE matchande relation(er)\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr " -s, --schema=MALL kontrollera matchande schema(n)\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr " -S, --exclude-schema=MALL kontrollera INTE matchande schema(n)\n" + +#: pg_amcheck.c:1177 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr " -t, --table=MALL kontollera matchande tabell(er)\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr " -T, --exclude-table=MALL kontollera INTE matchande tabell(er)\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid " --no-dependent-indexes do NOT expand list of relations to include indexes\n" +msgstr " --no-dependent-indexes expandera INTE listan med relationer för att inkludera index\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid " --no-dependent-toast do NOT expand list of relations to include TOAST tables\n" +msgstr " --no-dependent-toast expandera inte listan av relationer för att inkludera TOAST-tabeller\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid " --no-strict-names do NOT require patterns to match objects\n" +msgstr " --no-strict-names kräv INTE mallar för matcha objekt\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid "" +"\n" +"Table checking options:\n" +msgstr "" +"\n" +"Flaggor för kontroll av tabeller:\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid " --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr " --exclude-toast-pointers följ INTE relationers TOAST-pekare\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid " --on-error-stop stop checking at end of first corrupt page\n" +msgstr " --on-error-stop sluta kontrollera efter första korrupta sidan\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid " --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n" +msgstr " --skip=FLAGGA kontrollera INTE block som är \"all-frozen\" eller \"all-visible\"\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid " --startblock=BLOCK begin checking table(s) at the given block number\n" +msgstr " --startblock=BLOCK börja kontollera tabell(er) vid angivet blocknummer\n" + +#: pg_amcheck.c:1187 +#, c-format +msgid " --endblock=BLOCK check table(s) only up to the given block number\n" +msgstr " --endblock=BLOCK kontrollera tabell(er) fram till angivet blocknummer\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid "" +"\n" +"B-tree index checking options:\n" +msgstr "" +"\n" +"Flaggor för kontroll av B-tree-index:\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid " --heapallindexed check that all heap tuples are found within indexes\n" +msgstr " --heapallindexed kontrollera att alla heap-tupler hittas i index\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid " --parent-check check index parent/child relationships\n" +msgstr " --parent-check kontrollera förhållandet mellan barn/förälder i index\n" + +#: pg_amcheck.c:1191 +#, c-format +msgid " --rootdescend search from root page to refind tuples\n" +msgstr " --rootdescend sök från root-sidan för att återfinna tupler\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid "" +"\n" +"Connection options:\n" +msgstr "" +"\n" +"Flaggor för anslutning:\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid " -h, --host=HOSTNAME database server host or socket directory\n" +msgstr " -h, --host=VÄRDNAMN databasens värdnamn eller socketkatalog\n" + +#: pg_amcheck.c:1194 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=PORT databasserverns port\n" + +#: pg_amcheck.c:1195 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr " -U, --username=ANVÄNDARE användarnamn att ansluta som\n" + +#: pg_amcheck.c:1196 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password fråga ej efter lösenord\n" + +#: pg_amcheck.c:1197 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password tvinga fram lösenordsfråga\n" + +#: pg_amcheck.c:1198 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=DBNAMN val av underhållsdatabas\n" + +#: pg_amcheck.c:1199 +#, c-format +msgid "" +"\n" +"Other options:\n" +msgstr "" +"\n" +"Andra flaggor:\n" + +#: pg_amcheck.c:1200 +#, c-format +msgid " -e, --echo show the commands being sent to the server\n" +msgstr " -e, --echo visa kommandon som skickas till servern\n" + +#: pg_amcheck.c:1201 +#, c-format +msgid " -j, --jobs=NUM use this many concurrent connections to the server\n" +msgstr " -j, --jobs=NUM antal samtidiga anslutningar till servern\n" + +#: pg_amcheck.c:1202 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress visa förloppsinformation\n" + +#: pg_amcheck.c:1203 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose skriv massor med utdata\n" + +#: pg_amcheck.c:1204 +#, c-format +msgid " -V, --version output version information, then exit\n" +msgstr " -V, --version visa versionsinformation, avsluta sedan\n" + +#: pg_amcheck.c:1205 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing installera utökningar som saknas\n" + +#: pg_amcheck.c:1206 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help visa denna hjälp, avsluta sedan\n" + +#: pg_amcheck.c:1208 +#, c-format +msgid "" +"\n" +"Report bugs to <%s>.\n" +msgstr "" +"\n" +"Rapportera fel till <%s>.\n" + +#: pg_amcheck.c:1209 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "hemsida för %s: <%s>\n" + +#: pg_amcheck.c:1267 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "%*s/%s relationer (%d%%), %*s/%s sidor (%d%%) %*s" + +#: pg_amcheck.c:1278 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "%*s/%s relationer (%d%%), %*s/%s sidor (%d%%) (%s%-*.*s)" + +#: pg_amcheck.c:1293 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "%*s/%s relationer (%d%%), %*s/%s sidor (%d%%)" + +#: pg_amcheck.c:1352 pg_amcheck.c:1385 +#, c-format +msgid "improper qualified name (too many dotted names): %s" +msgstr "ej korrekt kvalificerat namn (för många namn med punkt): %s" + +#: pg_amcheck.c:1430 +#, c-format +msgid "improper relation name (too many dotted names): %s" +msgstr "ej korrekt relationsnamn (för många namn med punkt): %s" + +#: pg_amcheck.c:1583 pg_amcheck.c:1725 +#, c-format +msgid "including database \"%s\"" +msgstr "inkludera databas \"%s\"" + +#: pg_amcheck.c:1705 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "internt fel: tog emot oväntat pattern_id %d för databas" + +#: pg_amcheck.c:1709 +#, c-format +msgid "no connectable databases to check matching \"%s\"" +msgstr "finns inga anslutningsbara databaser att kontrollera som matchar \"%s\"" + +#: pg_amcheck.c:2168 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "internt fel: tog emot oväntat pattern_id %d för relation" diff --git a/src/bin/pg_amcheck/po/uk.po b/src/bin/pg_amcheck/po/uk.po new file mode 100644 index 0000000..4cd6bac --- /dev/null +++ b/src/bin/pg_amcheck/po/uk.po @@ -0,0 +1,506 @@ +msgid "" +msgstr "" +"Project-Id-Version: postgresql\n" +"Report-Msgid-Bugs-To: pgsql-bugs@lists.postgresql.org\n" +"POT-Creation-Date: 2022-06-16 04:04+0000\n" +"PO-Revision-Date: 2022-06-19 10:10\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_14_STABLE/pg_amcheck.pot\n" +"X-Crowdin-File-ID: 786\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 "попередження: " + +#: ../../fe_utils/cancel.c:189 ../../fe_utils/cancel.c:238 +msgid "Cancel request sent\n" +msgstr "Запит на скасування відправлений\n" + +#: ../../fe_utils/cancel.c:190 ../../fe_utils/cancel.c:239 +msgid "Could not send cancel request: " +msgstr "Не вдалося надіслати запит на скасування: " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "не можливо під'єднатися до бази даних %s: не вистачає пам'яті" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1680 pg_amcheck.c:2128 +#, c-format +msgid "query failed: %s" +msgstr "запит не вдався: %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:598 pg_amcheck.c:1130 pg_amcheck.c:1681 pg_amcheck.c:2129 +#, c-format +msgid "query was: %s" +msgstr "запит був: %s" + +#: pg_amcheck.c:330 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "число паралельних завдань повинно бути не менше 1" + +#: pg_amcheck.c:402 +#, c-format +msgid "invalid argument for option %s" +msgstr "неприпустимий аргумент для параметру %s" + +#: pg_amcheck.c:411 +#, c-format +msgid "invalid start block" +msgstr "неприпустимий початковий блок" + +#: pg_amcheck.c:416 +#, c-format +msgid "start block out of bounds" +msgstr "початковий блок поза межами" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "неприпустимий кінцевий блок" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "кінцевий блок поза межами" + +#: pg_amcheck.c:456 pg_amcheck.c:482 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "Спробуйте \"%s --help\" для додаткової інформації.\n" + +#: pg_amcheck.c:464 +#, c-format +msgid "end block precedes start block" +msgstr "кінцевий блок передує початковому блоку" + +#: pg_amcheck.c:480 +#, c-format +msgid "too many command-line arguments (first is \"%s\")" +msgstr "забагато аргументів у командному рядку (перший \"%s\")" + +#: pg_amcheck.c:501 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "не можна вказати назву бази даних з --all" + +#: pg_amcheck.c:510 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "не можна вказати одночасно ім'я бази даних і шаблони бази даних" + +#: pg_amcheck.c:540 +#, c-format +msgid "no databases to check" +msgstr "немає баз даних для перевірки" + +#: pg_amcheck.c:596 +#, c-format +msgid "database \"%s\": %s" +msgstr "база даних \"%s\": %s" + +#: pg_amcheck.c:607 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "пропуск бази даних \"%s\": amcheck не встановлено" + +#: pg_amcheck.c:615 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "у базі даних \"%s\": використовується amcheck версії \"%s\" у схемі \"%s\"" + +#: pg_amcheck.c:637 +#, c-format +msgid "no heap tables to check matching \"%s\"" +msgstr "немає таблиць в динамічній пам'яті для перевірки відповідності \"%s\"" + +#: pg_amcheck.c:640 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "немає індексів btree для перевірки відповідності \"%s\"" + +#: pg_amcheck.c:643 +#, c-format +msgid "no relations to check in schemas matching \"%s\"" +msgstr "немає відношень для перевірки в схемах, відповідних \"%s\"" + +#: pg_amcheck.c:646 +#, c-format +msgid "no relations to check matching \"%s\"" +msgstr "немає відношень для перевірки відповідності \"%s\"" + +#: pg_amcheck.c:674 +#, c-format +msgid "no relations to check" +msgstr "немає зв'язків для перевірки" + +#: pg_amcheck.c:758 +#, c-format +msgid "checking heap table \"%s.%s.%s\"" +msgstr "перевірка таблиць динамічної пам'яті \"%s.%s.%s\"" + +#: pg_amcheck.c:774 +#, c-format +msgid "checking btree index \"%s.%s.%s\"" +msgstr "перевірка індексу btree \"%s.%s.%s\"" + +#: pg_amcheck.c:921 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "помилка надсилання команди до бази даних \"%s: %s" + +#: pg_amcheck.c:924 +#, c-format +msgid "command was: %s" +msgstr "команда була: %s" + +#: pg_amcheck.c:1043 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "таблиця динамічної пам'яті \"%s.%s.%s\", блок %s, зсув %s, атрибут %s:\n" + +#: pg_amcheck.c:1050 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "таблиця динамічної пам'яті \"%s.%s.%s\", блок %s, зсув %s:\n" + +#: pg_amcheck.c:1056 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "таблиця динамічної пам'яті \"%s.%s.%s\", блок %s:\n" + +#: pg_amcheck.c:1061 pg_amcheck.c:1072 +#, c-format +msgid "heap table \"%s.%s.%s\":\n" +msgstr "таблиця динамічної пам'яті \"%s.%s.%s\":\n" + +#: pg_amcheck.c:1076 pg_amcheck.c:1145 +#, c-format +msgid "query was: %s\n" +msgstr "запит був: %s\n" + +#: pg_amcheck.c:1127 +#, c-format +msgid "btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d" +msgstr "індекс btree \"%s.%s.%s\": функція перевірки btree повернула неочікувану кількість рядків: %d" + +#: pg_amcheck.c:1131 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "Чи сумісні версії %s і amcheck?" + +#: pg_amcheck.c:1141 +#, c-format +msgid "btree index \"%s.%s.%s\":\n" +msgstr "індекс btree \"%s.%s.%s\":\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid "%s checks objects in a PostgreSQL database for corruption.\n\n" +msgstr "%s перевіряє об'єкти бази даних PostgreSQL на пошкодження.\n\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid "Usage:\n" +msgstr "Використання:\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [OPTION]... [DBNAME]\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid "\n" +"Target options:\n" +msgstr "\n" +"Цільові параметри:\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all перевірити всі бази даних\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr " -d, --database=PATTERN перевірити відповідні бази даних\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr " -D, --exclude-database=PATTERN НЕ перевіряти відповідні бази даних\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr " -i, --index=PATTERN перевірити відповідні індекси\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr " -I, --exclude-index=PATTERN НЕ перевіряти відповідні індекси\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr " -r, --relation=PATTERN перевірити відповідні відношення\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr " -R, --exclude-relation=PATTERN НЕ перевіряти відповідні відношення\n" + +#: pg_amcheck.c:1177 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr " -s, --schema=PATTERN перевірити відповідні схеми\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr " -S, --exclude-schema=PATTERN НЕ перевіряти відповідні схеми\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr " -t, --table=PATTERN перевірити відповідні таблиці\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr " -T, --exclude-table=PATTERN НЕ перевіряти відповідні таблиці\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid " --no-dependent-indexes do NOT expand list of relations to include indexes\n" +msgstr " --no-dependent-indexes НЕ розширювати список відносин, щоб включити індекси\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid " --no-dependent-toast do NOT expand list of relations to include TOAST tables\n" +msgstr " --no-dependent-toast НЕ розширювати список відносин, щоб включити таблиці TOAST\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid " --no-strict-names do NOT require patterns to match objects\n" +msgstr " --no-strict-names НЕ вимагати відповідності шаблонів об'єктам\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid "\n" +"Table checking options:\n" +msgstr "\n" +"Параметри перевірки таблиць:\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid " --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr " --exclude-toast-pointers НЕ слідувати покажчикам відношень TOAST\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid " --on-error-stop stop checking at end of first corrupt page\n" +msgstr " --on-error-stop зупинити перевірку наприкінці першої пошкодженої сторінки\n" + +#: pg_amcheck.c:1187 +#, c-format +msgid " --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n" +msgstr " --skip=OPTION НЕ перевіряти \"всі заморожені\" або \"всі видимі\" блоки\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid " --startblock=BLOCK begin checking table(s) at the given block number\n" +msgstr " --startblock=BLOCK почати перевірку таблиць за поданим номером блоку\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid " --endblock=BLOCK check table(s) only up to the given block number\n" +msgstr " --endblock=BLOCK перевіряти таблиці лише до поданого номеру блоку\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid "\n" +"B-tree index checking options:\n" +msgstr "\n" +"Параметри перевірки індексів B-tree:\n" + +#: pg_amcheck.c:1191 +#, c-format +msgid " --heapallindexed check that all heap tuples are found within indexes\n" +msgstr " --heapallindexed перевірити чи всі кортежі динамічної пам'яті містяться в індексах\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid " --parent-check check index parent/child relationships\n" +msgstr " --parent-check перевірити індекс батьківських/дочірніх відносин\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid " --rootdescend search from root page to refind tuples\n" +msgstr " --rootdescend шукати з кореневої сторінки, для повторного пошуку кортежів\n" + +#: pg_amcheck.c:1194 +#, c-format +msgid "\n" +"Connection options:\n" +msgstr "\n" +"Налаштування з'єднання:\n" + +#: pg_amcheck.c:1195 +#, c-format +msgid " -h, --host=HOSTNAME database server host or socket directory\n" +msgstr " -h, --host=HOSTNAME хост сервера бази даних або каталог сокетів\n" + +#: pg_amcheck.c:1196 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=PORT порт серверу бази даних\n" + +#: pg_amcheck.c:1197 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr " -U, --username=USERNAME ім'я користувача для з'єднання з сервером\n" + +#: pg_amcheck.c:1198 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password ніколи не запитувати пароль\n" + +#: pg_amcheck.c:1199 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password примусовий запит пароля\n" + +#: pg_amcheck.c:1200 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=DBNAME база даних альтернативного обслуговування\n" + +#: pg_amcheck.c:1201 +#, c-format +msgid "\n" +"Other options:\n" +msgstr "\n" +"Інші параметри:\n" + +#: pg_amcheck.c:1202 +#, c-format +msgid " -e, --echo show the commands being sent to the server\n" +msgstr " -e, --echo показати команди, надіслані серверу\n" + +#: pg_amcheck.c:1203 +#, c-format +msgid " -j, --jobs=NUM use this many concurrent connections to the server\n" +msgstr " -j, --jobs=NUM використати цю кількість одночасних з'єднань з сервером\n" + +#: pg_amcheck.c:1204 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress показати інформацію про прогрес\n" + +#: pg_amcheck.c:1205 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose виводити багато інформації\n" + +#: pg_amcheck.c:1206 +#, c-format +msgid " -V, --version output version information, then exit\n" +msgstr " -V, --version вивести інформацію про версію і вийти\n" + +#: pg_amcheck.c:1207 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing встановити відсутні розширення\n" + +#: pg_amcheck.c:1208 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help показати цю справку, потім вийти\n" + +#: pg_amcheck.c:1210 +#, c-format +msgid "\n" +"Report bugs to <%s>.\n" +msgstr "\n" +"Повідомляти про помилки на <%s>.\n" + +#: pg_amcheck.c:1211 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "Домашня сторінка %s: <%s>\n" + +#: pg_amcheck.c:1269 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "%*s/%s відношень (%d%%), %*s/%s сторінок (%d%%) %*s" + +#: pg_amcheck.c:1280 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "%*s/%s відношень (%d%%), %*s/%s сторінок (%d%%) (%s%-*.*s)" + +#: pg_amcheck.c:1295 +#, c-format +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "%*s/%s відношень (%d%%), %*s/%s сторінок (%d%%)" + +#: pg_amcheck.c:1354 pg_amcheck.c:1387 +#, c-format +msgid "improper qualified name (too many dotted names): %s" +msgstr "неправильне повне ім'я (забагато компонентів): %s" + +#: pg_amcheck.c:1432 +#, c-format +msgid "improper relation name (too many dotted names): %s" +msgstr "неправильне ім'я зв'язку (забагато компонентів): %s" + +#: pg_amcheck.c:1585 pg_amcheck.c:1727 +#, c-format +msgid "including database \"%s\"" +msgstr "включаючи базу даних \"%s\"" + +#: pg_amcheck.c:1707 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "внутрішня помилка: отримано неочікувану помилку шаблону бази даних %d" + +#: pg_amcheck.c:1711 +#, c-format +msgid "no connectable databases to check matching \"%s\"" +msgstr "немає бази даних для підключення, щоб перевірити відповідність\"%s\"" + +#: pg_amcheck.c:2170 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "внутрішня помилка: отримано неочікувану помилку шаблону відношення %d" + diff --git a/src/bin/pg_amcheck/po/zh_CN.po b/src/bin/pg_amcheck/po/zh_CN.po new file mode 100644 index 0000000..5ca9f01 --- /dev/null +++ b/src/bin/pg_amcheck/po/zh_CN.po @@ -0,0 +1,500 @@ +# LANGUAGE message translation file for pg_amcheck +# Copyright (C) 2021 PostgreSQL Global Development Group +# This file is distributed under the same license as the pg_amcheck (PostgreSQL) package. +# Jie Zhang <zhangjie2@fujitsu.com>, 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: pg_amcheck (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 18: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" + +#: ../../../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 "警告: " + +#: ../../fe_utils/cancel.c:161 ../../fe_utils/cancel.c:206 +msgid "Cancel request sent\n" +msgstr "取消发送的请求\n" + +#: ../../fe_utils/cancel.c:165 ../../fe_utils/cancel.c:210 +msgid "Could not send cancel request: " +msgstr "无法发送取消请求: " + +#: ../../fe_utils/connect_utils.c:92 +#, c-format +msgid "could not connect to database %s: out of memory" +msgstr "无法连接到数据库 %s:内存不足" + +#: ../../fe_utils/connect_utils.c:120 +#, c-format +msgid "%s" +msgstr "%s" + +#: ../../fe_utils/query_utils.c:33 ../../fe_utils/query_utils.c:58 +#: pg_amcheck.c:1646 pg_amcheck.c:2085 +#, c-format +msgid "query failed: %s" +msgstr "查询失败: %s" + +#: ../../fe_utils/query_utils.c:34 ../../fe_utils/query_utils.c:59 +#: pg_amcheck.c:597 pg_amcheck.c:1116 pg_amcheck.c:1647 pg_amcheck.c:2086 +#, c-format +msgid "query was: %s" +msgstr "查询是: %s" + +#: pg_amcheck.c:332 +#, c-format +msgid "number of parallel jobs must be at least 1" +msgstr "并行工作的数量必须至少为1" + +#: pg_amcheck.c:405 +#, c-format +msgid "invalid argument for option %s" +msgstr "选项%s的参数无效" + +#: pg_amcheck.c:413 +#, c-format +msgid "invalid start block" +msgstr "起始块无效" + +#: pg_amcheck.c:418 +#, c-format +msgid "start block out of bounds" +msgstr "起始块超出范围" + +#: pg_amcheck.c:426 +#, c-format +msgid "invalid end block" +msgstr "无效的结束块" + +#: pg_amcheck.c:431 +#, c-format +msgid "end block out of bounds" +msgstr "结束块超出范围" + +#: pg_amcheck.c:455 pg_amcheck.c:481 +#, c-format +msgid "Try \"%s --help\" for more information.\n" +msgstr "请用 \"%s --help\" 获取更多的信息.\n" + +#: pg_amcheck.c:463 +#, c-format +msgid "end block precedes start block" +msgstr "结束块在开始块之前" + +#: pg_amcheck.c:479 +#, c-format +msgid "too many command-line arguments (first is \"%s\")" +msgstr "命令行参数太多 (第一个是 \"%s\")" + +#: pg_amcheck.c:500 +#, c-format +msgid "cannot specify a database name with --all" +msgstr "无法使用--all指定数据库名称" + +#: pg_amcheck.c:509 +#, c-format +msgid "cannot specify both a database name and database patterns" +msgstr "不能同时指定数据库名称和数据库模式" + +#: pg_amcheck.c:539 +#, c-format +msgid "no databases to check" +msgstr "没有要检查的数据库" + +#: pg_amcheck.c:595 +#, c-format +msgid "database \"%s\": %s" +msgstr "数据库 \"%s\": %s" + +#: pg_amcheck.c:606 +#, c-format +msgid "skipping database \"%s\": amcheck is not installed" +msgstr "正在跳过数据库\"%s\":未安装amcheck" + +#: pg_amcheck.c:614 +#, c-format +msgid "in database \"%s\": using amcheck version \"%s\" in schema \"%s\"" +msgstr "在数据库\"%1$s\"中:在模式\"%3$s\"中使用amcheck版本\"%2$s\"" + +#: pg_amcheck.c:638 +msgid "no heap tables to check matching \"%s\"" +msgstr "没有要检查匹配\"%s\"的堆表" + +#: pg_amcheck.c:641 +#, c-format +msgid "no btree indexes to check matching \"%s\"" +msgstr "没有要检查匹配\"%s\"的B树索引" + +#: pg_amcheck.c:644 +msgid "no relations to check in schemas matching \"%s\"" +msgstr "在模式中没有要检查匹配\"%s\"的关系" + +#: pg_amcheck.c:647 +msgid "no relations to check matching \"%s\"" +msgstr "没有要检查匹配\"%s\"的关系" + +#: pg_amcheck.c:676 +#, c-format +msgid "no relations to check" +msgstr "没有要检查的关系" + +#: pg_amcheck.c:762 +msgid "checking heap table \"%s.%s.%s\"" +msgstr "正在检查堆表\"%s.%s.%s\"" + +#: pg_amcheck.c:778 +msgid "checking btree index \"%s.%s.%s\"" +msgstr "检查B树索引\"%s.%s.%s\"" + +#: pg_amcheck.c:911 +#, c-format +msgid "error sending command to database \"%s\": %s" +msgstr "向数据库\"%s\"发送命令时出错: %s" + +#: pg_amcheck.c:914 +#, c-format +msgid "command was: %s" +msgstr "命令是: %s" + +#: pg_amcheck.c:1031 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s, attribute %s:\n" +msgstr "堆表\"%s.%s.%s\",块%s,偏移量%s,属性%s:\n" + +#: pg_amcheck.c:1038 +#, c-format +msgid "heap table \"%s.%s.%s\", block %s, offset %s:\n" +msgstr "堆表\"%s.%s.%s\",块%s,偏移量%s:\n" + +#: pg_amcheck.c:1044 +msgid "heap table \"%s.%s.%s\", block %s:\n" +msgstr "堆表\"%s.%s.%s\",块%s:\n" + +#: pg_amcheck.c:1049 pg_amcheck.c:1060 +msgid "heap table \"%s.%s.%s\":\n" +msgstr "堆表\"%s.%s.%s\":\n" + +#: pg_amcheck.c:1064 pg_amcheck.c:1131 +msgid "query was: %s\n" +msgstr "查询是: %s\n" + +#: pg_amcheck.c:1113 +msgid "btree index \"%s.%s.%s\": btree checking function returned unexpected number of rows: %d" +msgstr "B树索引\"%s.%s.%s\":B树检查函数返回了意外的行数: %d" + +#: pg_amcheck.c:1117 +#, c-format +msgid "Are %s's and amcheck's versions compatible?" +msgstr "%s和amcheck的版本兼容吗?" + +#: pg_amcheck.c:1127 +msgid "btree index \"%s.%s.%s\":\n" +msgstr "B树索引\"%s.%s.%s\":\n" + +#: pg_amcheck.c:1152 +#, c-format +msgid "" +"%s checks objects in a PostgreSQL database for corruption.\n" +"\n" +msgstr "" +"%s检查PostgreSQL数据库中的对象是否损坏.\n" +"\n" + +#: pg_amcheck.c:1153 +#, c-format +msgid "Usage:\n" +msgstr "使用方法:\n" + +#: pg_amcheck.c:1154 +#, c-format +msgid " %s [OPTION]... [DBNAME]\n" +msgstr " %s [选项]... [数据库名字]\n" + +#: pg_amcheck.c:1155 +#, c-format +msgid "" +"\n" +"Target options:\n" +msgstr "" +"\n" +"目标选项:\n" + +#: pg_amcheck.c:1156 +#, c-format +msgid " -a, --all check all databases\n" +msgstr " -a, --all 检查所有数据库\n" + +#: pg_amcheck.c:1157 +#, c-format +msgid " -d, --database=PATTERN check matching database(s)\n" +msgstr " -d, --database=PATTERN 检查匹配的数据库\n" + +#: pg_amcheck.c:1158 +#, c-format +msgid " -D, --exclude-database=PATTERN do NOT check matching database(s)\n" +msgstr " -D, --exclude-database=PATTERN 不检查匹配的数据库\n" + +#: pg_amcheck.c:1159 +#, c-format +msgid " -i, --index=PATTERN check matching index(es)\n" +msgstr " -i, --index=PATTERN 检查匹配的索引\n" + +#: pg_amcheck.c:1160 +#, c-format +msgid " -I, --exclude-index=PATTERN do NOT check matching index(es)\n" +msgstr " -I, --exclude-index=PATTERN 不检查匹配的索引\n" + +#: pg_amcheck.c:1161 +#, c-format +msgid " -r, --relation=PATTERN check matching relation(s)\n" +msgstr " -r, --relation=PATTERN 检查匹配的关系\n" + +#: pg_amcheck.c:1162 +#, c-format +msgid " -R, --exclude-relation=PATTERN do NOT check matching relation(s)\n" +msgstr " -R, --exclude-relation=PATTERN 不检查匹配的关系\n" + +#: pg_amcheck.c:1163 +#, c-format +msgid " -s, --schema=PATTERN check matching schema(s)\n" +msgstr " -s, --schema=PATTERN 检查匹配的模式\n" + +#: pg_amcheck.c:1164 +#, c-format +msgid " -S, --exclude-schema=PATTERN do NOT check matching schema(s)\n" +msgstr " -S, --exclude-schema=PATTERN 不检查匹配模式\n" + +#: pg_amcheck.c:1165 +#, c-format +msgid " -t, --table=PATTERN check matching table(s)\n" +msgstr " -t, --table=PATTERN 检查匹配的表\n" + +#: pg_amcheck.c:1166 +#, c-format +msgid " -T, --exclude-table=PATTERN do NOT check matching table(s)\n" +msgstr " -T, --exclude-table=PATTERN 不检查匹的配表\n" + +#: pg_amcheck.c:1167 +#, c-format +msgid " --no-dependent-indexes do NOT expand list of relations to include indexes\n" +msgstr " --no-dependent-indexes 不要展开关系列表以包含索引\n" + +#: pg_amcheck.c:1168 +#, c-format +msgid " --no-dependent-toast do NOT expand list of relations to include TOAST tables\n" +msgstr " --no-dependent-toast 不要展开关系列表以包括TOAST表\n" + +#: pg_amcheck.c:1169 +#, c-format +msgid " --no-strict-names do NOT require patterns to match objects\n" +msgstr " --no-strict-names 不需要模式来匹配对象\n" + +#: pg_amcheck.c:1170 +#, c-format +msgid "" +"\n" +"Table checking options:\n" +msgstr "" +"\n" +"表检查选项:\n" + +#: pg_amcheck.c:1171 +#, c-format +msgid " --exclude-toast-pointers do NOT follow relation TOAST pointers\n" +msgstr " --exclude-toast-pointers 不要遵循关系TOAST指示\n" + +#: pg_amcheck.c:1172 +#, c-format +msgid " --on-error-stop stop checking at end of first corrupt page\n" +msgstr " --on-error-stop 在第一个损坏页的末尾停止检查\n" + +#: pg_amcheck.c:1173 +#, c-format +msgid " --skip=OPTION do NOT check \"all-frozen\" or \"all-visible\" blocks\n" +msgstr " --skip=OPTION 不要检查\"all-frozen\"或\"all-visible\"块\n" + +#: pg_amcheck.c:1174 +#, c-format +msgid " --startblock=BLOCK begin checking table(s) at the given block number\n" +msgstr " --startblock=BLOCK 在给定的块编号处开始检查表\n" + +#: pg_amcheck.c:1175 +#, c-format +msgid " --endblock=BLOCK check table(s) only up to the given block number\n" +msgstr " --endblock=BLOCK 检查表仅限于给定的块编号\n" + +#: pg_amcheck.c:1176 +#, c-format +msgid "" +"\n" +"B-tree index checking options:\n" +msgstr "" +"\n" +"B树索引检查选项:\n" + +#: pg_amcheck.c:1177 +msgid " --heapallindexed check that all heap tuples are found within indexes\n" +msgstr " --heapallindexed 检查是否在索引中找到所有堆元组\n" + +#: pg_amcheck.c:1178 +#, c-format +msgid " --parent-check check index parent/child relationships\n" +msgstr " --parent-check 检查索引父/子关系\n" + +#: pg_amcheck.c:1179 +#, c-format +msgid " --rootdescend search from root page to refind tuples\n" +msgstr " --rootdescend 从根页搜索到重新填充元组\n" + +#: pg_amcheck.c:1180 +#, c-format +msgid "" +"\n" +"Connection options:\n" +msgstr "" +"\n" +"联接选项:\n" + +#: pg_amcheck.c:1181 +#, c-format +msgid " -h, --host=HOSTNAME database server host or socket directory\n" +msgstr " -h, --host=HOSTNAME 数据库服务器主机或套接字目录\n" + +#: pg_amcheck.c:1182 +#, c-format +msgid " -p, --port=PORT database server port\n" +msgstr " -p, --port=PORT 数据库服务器端口\n" + +#: pg_amcheck.c:1183 +#, c-format +msgid " -U, --username=USERNAME user name to connect as\n" +msgstr " -U, --username=USERNAME 要连接的用户名\n" + +#: pg_amcheck.c:1184 +#, c-format +msgid " -w, --no-password never prompt for password\n" +msgstr " -w, --no-password 从不提示输入密码\n" + +#: pg_amcheck.c:1185 +#, c-format +msgid " -W, --password force password prompt\n" +msgstr " -W, --password 强制密码提示\n" + +#: pg_amcheck.c:1186 +#, c-format +msgid " --maintenance-db=DBNAME alternate maintenance database\n" +msgstr " --maintenance-db=DBNAME 备用维护数据库\n" + +#: pg_amcheck.c:1187 +#, c-format +msgid "" +"\n" +"Other options:\n" +msgstr "" +"\n" +"其它选项:\n" + +#: pg_amcheck.c:1188 +#, c-format +msgid " -e, --echo show the commands being sent to the server\n" +msgstr " -e, --echo 显示发送到服务端的命令\n" + +#: pg_amcheck.c:1189 +#, c-format +msgid " -j, --jobs=NUM use this many concurrent connections to the server\n" +msgstr " -j, --jobs=NUM 使用这么多到服务器的并发连接\n" + +#: pg_amcheck.c:1190 +#, c-format +msgid " -q, --quiet don't write any messages\n" +msgstr " -q, --quiet 不写任何信息\n" + +#: pg_amcheck.c:1191 +#, c-format +msgid " -P, --progress show progress information\n" +msgstr " -P, --progress 显示进度信息\n" + +#: pg_amcheck.c:1192 +#, c-format +msgid " -v, --verbose write a lot of output\n" +msgstr " -v, --verbose 写大量的输出\n" + +#: pg_amcheck.c:1193 +#, c-format +msgid " -V, --version output version information, then exit\n" +msgstr " -V, --version 输出版本信息, 然后退出\n" + +#: pg_amcheck.c:1194 +#, c-format +msgid " --install-missing install missing extensions\n" +msgstr " --install-missing 安装缺少的扩展\n" + +#: pg_amcheck.c:1195 +#, c-format +msgid " -?, --help show this help, then exit\n" +msgstr " -?, --help 显示此帮助信息, 然后退出\n" + +#: pg_amcheck.c:1197 +#, c-format +msgid "" +"\n" +"Report bugs to <%s>.\n" +msgstr "" +"\n" +"臭虫报告至<%s>.\n" + +#: pg_amcheck.c:1198 +#, c-format +msgid "%s home page: <%s>\n" +msgstr "%s 主页: <%s>\n" + +#: pg_amcheck.c:1256 +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) %*s" +msgstr "%*s/%s 关系 (%d%%), %*s/%s 页 (%d%%) %*s" + +#: pg_amcheck.c:1267 +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%) (%s%-*.*s)" +msgstr "%*s/%s 关系 (%d%%), %*s/%s 页 (%d%%) (%s%-*.*s)" + +#: pg_amcheck.c:1282 +msgid "%*s/%s relations (%d%%), %*s/%s pages (%d%%)" +msgstr "%*s/%s 关系 (%d%%), %*s/%s 页 (%d%%)" + +#: pg_amcheck.c:1551 pg_amcheck.c:1693 +#, c-format +msgid "including database \"%s\"" +msgstr "包含的数据库\"%s\"" + +#: pg_amcheck.c:1673 +#, c-format +msgid "internal error: received unexpected database pattern_id %d" +msgstr "内部错误:收到意外的数据库pattern_id %d" + +#: pg_amcheck.c:1677 +msgid "no connectable databases to check matching \"%s\"" +msgstr "没有可连接的数据库来检查匹配的\"%s\"" + +#: pg_amcheck.c:2127 +#, c-format +msgid "internal error: received unexpected relation pattern_id %d" +msgstr "内部错误:收到意外的关系pattern_id %d" diff --git a/src/bin/pg_amcheck/t/001_basic.pl b/src/bin/pg_amcheck/t/001_basic.pl new file mode 100644 index 0000000..6f60e3e --- /dev/null +++ b/src/bin/pg_amcheck/t/001_basic.pl @@ -0,0 +1,12 @@ + +# Copyright (c) 2021, PostgreSQL Global Development Group + +use strict; +use warnings; + +use TestLib; +use Test::More tests => 8; + +program_help_ok('pg_amcheck'); +program_version_ok('pg_amcheck'); +program_options_handling_ok('pg_amcheck'); diff --git a/src/bin/pg_amcheck/t/002_nonesuch.pl b/src/bin/pg_amcheck/t/002_nonesuch.pl new file mode 100644 index 0000000..df0cb03 --- /dev/null +++ b/src/bin/pg_amcheck/t/002_nonesuch.pl @@ -0,0 +1,359 @@ + +# Copyright (c) 2021, PostgreSQL Global Development Group + +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 100; + +# Test set-up +my ($node, $port); +$node = get_new_node('test'); +$node->init; +$node->start; +$port = $node->port; + +# Load the amcheck extension, upon which pg_amcheck depends +$node->safe_psql('postgres', q(CREATE EXTENSION amcheck)); + +######################################### +# Test non-existent databases + +# Failing to connect to the initial database is an error. +$node->command_checks_all( + [ 'pg_amcheck', 'qqq' ], + 1, [qr/^$/], + [qr/FATAL: database "qqq" does not exist/], + 'checking a non-existent database'); + +# Failing to resolve a database pattern is an error by default. +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'qqq', '-d', 'postgres' ], + 1, + [qr/^$/], + [qr/pg_amcheck: error: no connectable databases to check matching "qqq"/], + 'checking an unresolvable database pattern'); + +# But only a warning under --no-strict-names +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-d', 'qqq', '-d', 'postgres' ], + 0, + [qr/^$/], + [ + qr/pg_amcheck: warning: no connectable databases to check matching "qqq"/ + ], + 'checking an unresolvable database pattern under --no-strict-names'); + +# Check that a substring of an existent database name does not get interpreted +# as a matching pattern. +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'post', '-d', 'postgres' ], + 1, + [qr/^$/], + [ + qr/pg_amcheck: error: no connectable databases to check matching "post"/ + ], + 'checking an unresolvable database pattern (substring of existent database)' +); + +# Check that a superstring of an existent database name does not get interpreted +# as a matching pattern. +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'postgresql', '-d', 'postgres' ], + 1, + [qr/^$/], + [ + qr/pg_amcheck: error: no connectable databases to check matching "postgresql"/ + ], + 'checking an unresolvable database pattern (superstring of existent database)' +); + +######################################### +# Test connecting with a non-existent user + +# Failing to connect to the initial database due to bad username is an error. +$node->command_checks_all([ 'pg_amcheck', '-U', 'no_such_user', 'postgres' ], + 1, [qr/^$/], [], 'checking with a non-existent user'); + +######################################### +# Test checking databases without amcheck installed + +# Attempting to check a database by name where amcheck is not installed should +# raise a warning. If all databases are skipped, having no relations to check +# raises an error. +$node->command_checks_all( + [ 'pg_amcheck', 'template1' ], + 1, + [qr/^$/], + [ + qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/, + qr/pg_amcheck: error: no relations to check/ + ], + 'checking a database by name without amcheck installed, no other databases' +); + +# Again, but this time with another database to check, so no error is raised. +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'template1', '-d', 'postgres' ], + 0, + [qr/^$/], + [ + qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/ + ], + 'checking a database by name without amcheck installed, with other databases' +); + +# Again, but by way of checking all databases +$node->command_checks_all( + [ 'pg_amcheck', '--all' ], + 0, + [qr/^$/], + [ + qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/ + ], + 'checking a database by pattern without amcheck installed, with other databases' +); + +######################################### +# Test unreasonable patterns + +# Check three-part unreasonable pattern that has zero-length names +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'postgres', '-t', '..' ], + 1, + [qr/^$/], + [ + qr/pg_amcheck: error: no connectable databases to check matching "\.\."/ + ], + 'checking table pattern ".."'); + +# Again, but with non-trivial schema and relation parts +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'postgres', '-t', '.foo.bar' ], + 1, + [qr/^$/], + [ + qr/pg_amcheck: error: no connectable databases to check matching "\.foo\.bar"/ + ], + 'checking table pattern ".foo.bar"'); + +# Check two-part unreasonable pattern that has zero-length names +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'postgres', '-t', '.' ], + 1, + [qr/^$/], + [qr/pg_amcheck: error: no heap tables to check matching "\."/], + 'checking table pattern "."'); + +# Check that a multipart database name is rejected +$node->command_checks_all( + [ 'pg_amcheck', '-d', 'localhost.postgres' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): localhost\.postgres/ + ], + 'multipart database patterns are rejected' +); + +# Check that a three-part schema name is rejected +$node->command_checks_all( + [ 'pg_amcheck', '-s', 'localhost.postgres.pg_catalog' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): localhost\.postgres\.pg_catalog/ + ], + 'three part schema patterns are rejected' +); + +# Check that a four-part table name is rejected +$node->command_checks_all( + [ 'pg_amcheck', '-t', 'localhost.postgres.pg_catalog.pg_class' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper relation name \(too many dotted names\): localhost\.postgres\.pg_catalog\.pg_class/ + ], + 'four part table patterns are rejected' +); + +# Check that too many dotted names still draws an error under --no-strict-names +# That flag means that it is ok for the object to be missing, not that it is ok +# for the object name to be ungrammatical +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-t', 'this.is.a.really.long.dotted.string' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper relation name \(too many dotted names\): this\.is\.a\.really\.long\.dotted\.string/ + ], + 'ungrammatical table names still draw errors under --no-strict-names' +); +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-s', 'postgres.long.dotted.string' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): postgres\.long\.dotted\.string/ + ], + 'ungrammatical schema names still draw errors under --no-strict-names' +); +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-d', 'postgres.long.dotted.string' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): postgres\.long\.dotted\.string/ + ], + 'ungrammatical database names still draw errors under --no-strict-names' +); + +# Likewise for exclusion patterns +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-T', 'a.b.c.d' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper relation name \(too many dotted names\): a\.b\.c\.d/ + ], + 'ungrammatical table exclusions still draw errors under --no-strict-names' +); +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-S', 'a.b.c' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): a\.b\.c/ + ], + 'ungrammatical schema exclusions still draw errors under --no-strict-names' +); +$node->command_checks_all( + [ 'pg_amcheck', '--no-strict-names', '-D', 'a.b' ], + 2, + [qr/^$/], + [ + qr/pg_amcheck: error: improper qualified name \(too many dotted names\): a\.b/ + ], + 'ungrammatical database exclusions still draw errors under --no-strict-names' +); + + +######################################### +# Test checking non-existent databases, schemas, tables, and indexes + +# Use --no-strict-names and a single existent table so we only get warnings +# about the failed pattern matches +$node->command_checks_all( + [ + 'pg_amcheck', '--no-strict-names', + '-t', 'no_such_table', + '-t', 'no*such*table', + '-i', 'no_such_index', + '-i', 'no*such*index', + '-r', 'no_such_relation', + '-r', 'no*such*relation', + '-d', 'no_such_database', + '-d', 'no*such*database', + '-r', 'none.none', + '-r', 'none.none.none', + '-r', 'postgres.none.none', + '-r', 'postgres.pg_catalog.none', + '-r', 'postgres.none.pg_class', + '-t', 'postgres.pg_catalog.pg_class', # This exists + ], + 0, + [qr/^$/], + [ + qr/pg_amcheck: warning: no heap tables to check matching "no_such_table"/, + qr/pg_amcheck: warning: no heap tables to check matching "no\*such\*table"/, + qr/pg_amcheck: warning: no btree indexes to check matching "no_such_index"/, + qr/pg_amcheck: warning: no btree indexes to check matching "no\*such\*index"/, + qr/pg_amcheck: warning: no relations to check matching "no_such_relation"/, + qr/pg_amcheck: warning: no relations to check matching "no\*such\*relation"/, + qr/pg_amcheck: warning: no heap tables to check matching "no\*such\*table"/, + qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database"/, + qr/pg_amcheck: warning: no connectable databases to check matching "no\*such\*database"/, + qr/pg_amcheck: warning: no relations to check matching "none\.none"/, + qr/pg_amcheck: warning: no connectable databases to check matching "none\.none\.none"/, + qr/pg_amcheck: warning: no relations to check matching "postgres\.none\.none"/, + qr/pg_amcheck: warning: no relations to check matching "postgres\.pg_catalog\.none"/, + qr/pg_amcheck: warning: no relations to check matching "postgres\.none\.pg_class"/, + qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database"/, + qr/pg_amcheck: warning: no connectable databases to check matching "no\*such\*database"/, + qr/pg_amcheck: warning: no connectable databases to check matching "none\.none\.none"/, + ], + 'many unmatched patterns and one matched pattern under --no-strict-names' +); + +######################################### +# Test checking otherwise existent objects but in databases where they do not exist + +$node->safe_psql( + 'postgres', q( + CREATE TABLE public.foo (f integer); + CREATE INDEX foo_idx ON foo(f); +)); +$node->safe_psql('postgres', q(CREATE DATABASE another_db)); + +$node->command_checks_all( + [ + 'pg_amcheck', '-d', + 'postgres', '--no-strict-names', + '-t', 'template1.public.foo', + '-t', 'another_db.public.foo', + '-t', 'no_such_database.public.foo', + '-i', 'template1.public.foo_idx', + '-i', 'another_db.public.foo_idx', + '-i', 'no_such_database.public.foo_idx', + ], + 1, + [qr/^$/], + [ + qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/, + qr/pg_amcheck: warning: no heap tables to check matching "template1\.public\.foo"/, + qr/pg_amcheck: warning: no heap tables to check matching "another_db\.public\.foo"/, + qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database\.public\.foo"/, + qr/pg_amcheck: warning: no btree indexes to check matching "template1\.public\.foo_idx"/, + qr/pg_amcheck: warning: no btree indexes to check matching "another_db\.public\.foo_idx"/, + qr/pg_amcheck: warning: no connectable databases to check matching "no_such_database\.public\.foo_idx"/, + qr/pg_amcheck: error: no relations to check/, + ], + 'checking otherwise existent objets in the wrong databases'); + + +######################################### +# Test schema exclusion patterns + +# Check with only schema exclusion patterns +$node->command_checks_all( + [ + 'pg_amcheck', '--all', '--no-strict-names', '-S', + 'public', '-S', 'pg_catalog', '-S', + 'pg_toast', '-S', 'information_schema', + ], + 1, + [qr/^$/], + [ + qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/, + qr/pg_amcheck: error: no relations to check/ + ], + 'schema exclusion patterns exclude all relations'); + +# Check with schema exclusion patterns overriding relation and schema inclusion patterns +$node->command_checks_all( + [ + 'pg_amcheck', '--all', '--no-strict-names', '-s', + 'public', '-s', 'pg_catalog', '-s', + 'pg_toast', '-s', 'information_schema', '-t', + 'pg_catalog.pg_class', '-S*' + ], + 1, + [qr/^$/], + [ + qr/pg_amcheck: warning: skipping database "template1": amcheck is not installed/, + qr/pg_amcheck: error: no relations to check/ + ], + 'schema exclusion pattern overrides all inclusion patterns'); diff --git a/src/bin/pg_amcheck/t/003_check.pl b/src/bin/pg_amcheck/t/003_check.pl new file mode 100644 index 0000000..4122d72 --- /dev/null +++ b/src/bin/pg_amcheck/t/003_check.pl @@ -0,0 +1,518 @@ + +# Copyright (c) 2021, PostgreSQL Global Development Group + +use strict; +use warnings; + +use PostgresNode; +use TestLib; + +use Test::More tests => 63; + +my ($node, $port, %corrupt_page, %remove_relation); + +# Returns the filesystem path for the named relation. +# +# Assumes the test node is running +sub relation_filepath +{ + my ($dbname, $relname) = @_; + + my $pgdata = $node->data_dir; + my $rel = + $node->safe_psql($dbname, qq(SELECT pg_relation_filepath('$relname'))); + die "path not found for relation $relname" unless defined $rel; + return "$pgdata/$rel"; +} + +# Returns the name of the toast relation associated with the named relation. +# +# Assumes the test node is running +sub relation_toast +{ + my ($dbname, $relname) = @_; + + my $rel = $node->safe_psql( + $dbname, qq( + SELECT c.reltoastrelid::regclass + FROM pg_catalog.pg_class c + WHERE c.oid = '$relname'::regclass + AND c.reltoastrelid != 0 + )); + return $rel; +} + +# Adds the relation file for the given (dbname, relname) to the list +# to be corrupted by means of overwriting junk in the first page. +# +# Assumes the test node is running. +sub plan_to_corrupt_first_page +{ + my ($dbname, $relname) = @_; + my $relpath = relation_filepath($dbname, $relname); + $corrupt_page{$relpath} = 1; +} + +# Adds the relation file for the given (dbname, relname) to the list +# to be corrupted by means of removing the file.. +# +# Assumes the test node is running +sub plan_to_remove_relation_file +{ + my ($dbname, $relname) = @_; + my $relpath = relation_filepath($dbname, $relname); + $remove_relation{$relpath} = 1; +} + +# For the given (dbname, relname), if a corresponding toast table +# exists, adds that toast table's relation file to the list to be +# corrupted by means of removing the file. +# +# Assumes the test node is running. +sub plan_to_remove_toast_file +{ + my ($dbname, $relname) = @_; + my $toastname = relation_toast($dbname, $relname); + plan_to_remove_relation_file($dbname, $toastname) if ($toastname); +} + +# Corrupts the first page of the given file path +sub corrupt_first_page +{ + my ($relpath) = @_; + + my $fh; + open($fh, '+<', $relpath) + or BAIL_OUT("open failed: $!"); + binmode $fh; + + # Corrupt some line pointers. The values are chosen to hit the + # various line-pointer-corruption checks in verify_heapam.c + # on both little-endian and big-endian architectures. + sysseek($fh, 32, 0) + or BAIL_OUT("sysseek failed: $!"); + syswrite( + $fh, + pack("L*", + 0xAAA15550, 0xAAA0D550, 0x00010000, 0x00008000, + 0x0000800F, 0x001e8000, 0xFFFFFFFF) + ) or BAIL_OUT("syswrite failed: $!"); + close($fh) + or BAIL_OUT("close failed: $!"); +} + +# Stops the node, performs all the corruptions previously planned, and +# starts the node again. +# +sub perform_all_corruptions() +{ + $node->stop(); + for my $relpath (keys %corrupt_page) + { + corrupt_first_page($relpath); + } + for my $relpath (keys %remove_relation) + { + unlink($relpath); + } + $node->start; +} + +# Test set-up +$node = get_new_node('test'); +$node->init; +$node->append_conf('postgresql.conf', 'autovacuum=off'); +$node->start; +$port = $node->port; + +for my $dbname (qw(db1 db2 db3)) +{ + # Create the database + $node->safe_psql('postgres', qq(CREATE DATABASE $dbname)); + + # Load the amcheck extension, upon which pg_amcheck depends. Put the + # extension in an unexpected location to test that pg_amcheck finds it + # correctly. Create tables with names that look like pg_catalog names to + # check that pg_amcheck does not get confused by them. Create functions in + # schema public that look like amcheck functions to check that pg_amcheck + # does not use them. + $node->safe_psql( + $dbname, q( + CREATE SCHEMA amcheck_schema; + CREATE EXTENSION amcheck WITH SCHEMA amcheck_schema; + CREATE TABLE amcheck_schema.pg_database (junk text); + CREATE TABLE amcheck_schema.pg_namespace (junk text); + CREATE TABLE amcheck_schema.pg_class (junk text); + CREATE TABLE amcheck_schema.pg_operator (junk text); + CREATE TABLE amcheck_schema.pg_proc (junk text); + CREATE TABLE amcheck_schema.pg_tablespace (junk text); + + CREATE FUNCTION public.bt_index_check(index regclass, + heapallindexed boolean default false) + RETURNS VOID AS $$ + BEGIN + RAISE EXCEPTION 'Invoked wrong bt_index_check!'; + END; + $$ LANGUAGE plpgsql; + + CREATE FUNCTION public.bt_index_parent_check(index regclass, + heapallindexed boolean default false, + rootdescend boolean default false) + RETURNS VOID AS $$ + BEGIN + RAISE EXCEPTION 'Invoked wrong bt_index_parent_check!'; + END; + $$ LANGUAGE plpgsql; + + CREATE FUNCTION public.verify_heapam(relation regclass, + on_error_stop boolean default false, + check_toast boolean default false, + skip text default 'none', + startblock bigint default null, + endblock bigint default null, + blkno OUT bigint, + offnum OUT integer, + attnum OUT integer, + msg OUT text) + RETURNS SETOF record AS $$ + BEGIN + RAISE EXCEPTION 'Invoked wrong verify_heapam!'; + END; + $$ LANGUAGE plpgsql; + )); + + # Create schemas, tables and indexes in five separate + # schemas. The schemas are all identical to start, but + # we will corrupt them differently later. + # + for my $schema (qw(s1 s2 s3 s4 s5)) + { + $node->safe_psql( + $dbname, qq( + CREATE SCHEMA $schema; + CREATE SEQUENCE $schema.seq1; + CREATE SEQUENCE $schema.seq2; + CREATE TABLE $schema.t1 ( + i INTEGER, + b BOX, + ia int4[], + ir int4range, + t TEXT + ); + CREATE TABLE $schema.t2 ( + i INTEGER, + b BOX, + ia int4[], + ir int4range, + t TEXT + ); + CREATE VIEW $schema.t2_view AS ( + SELECT i*2, t FROM $schema.t2 + ); + ALTER TABLE $schema.t2 + ALTER COLUMN t + SET STORAGE EXTERNAL; + + INSERT INTO $schema.t1 (i, b, ia, ir, t) + (SELECT gs::INTEGER AS i, + box(point(gs,gs+5),point(gs*2,gs*3)) AS b, + array[gs, gs + 1]::int4[] AS ia, + int4range(gs, gs+100) AS ir, + repeat('foo', gs) AS t + FROM generate_series(1,10000,3000) AS gs); + + INSERT INTO $schema.t2 (i, b, ia, ir, t) + (SELECT gs::INTEGER AS i, + box(point(gs,gs+5),point(gs*2,gs*3)) AS b, + array[gs, gs + 1]::int4[] AS ia, + int4range(gs, gs+100) AS ir, + repeat('foo', gs) AS t + FROM generate_series(1,10000,3000) AS gs); + + CREATE MATERIALIZED VIEW $schema.t1_mv AS SELECT * FROM $schema.t1; + CREATE MATERIALIZED VIEW $schema.t2_mv AS SELECT * FROM $schema.t2; + + create table $schema.p1 (a int, b int) PARTITION BY list (a); + create table $schema.p2 (a int, b int) PARTITION BY list (a); + + create table $schema.p1_1 partition of $schema.p1 for values in (1, 2, 3); + create table $schema.p1_2 partition of $schema.p1 for values in (4, 5, 6); + create table $schema.p2_1 partition of $schema.p2 for values in (1, 2, 3); + create table $schema.p2_2 partition of $schema.p2 for values in (4, 5, 6); + + CREATE INDEX t1_btree ON $schema.t1 USING BTREE (i); + CREATE INDEX t2_btree ON $schema.t2 USING BTREE (i); + + CREATE INDEX t1_hash ON $schema.t1 USING HASH (i); + CREATE INDEX t2_hash ON $schema.t2 USING HASH (i); + + CREATE INDEX t1_brin ON $schema.t1 USING BRIN (i); + CREATE INDEX t2_brin ON $schema.t2 USING BRIN (i); + + CREATE INDEX t1_gist ON $schema.t1 USING GIST (b); + CREATE INDEX t2_gist ON $schema.t2 USING GIST (b); + + CREATE INDEX t1_gin ON $schema.t1 USING GIN (ia); + CREATE INDEX t2_gin ON $schema.t2 USING GIN (ia); + + CREATE INDEX t1_spgist ON $schema.t1 USING SPGIST (ir); + CREATE INDEX t2_spgist ON $schema.t2 USING SPGIST (ir); + )); + } +} + +# Database 'db1' corruptions +# + +# Corrupt indexes in schema "s1" +plan_to_remove_relation_file('db1', 's1.t1_btree'); +plan_to_corrupt_first_page('db1', 's1.t2_btree'); + +# Corrupt tables in schema "s2" +plan_to_remove_relation_file('db1', 's2.t1'); +plan_to_corrupt_first_page('db1', 's2.t2'); + +# Corrupt tables, partitions, matviews, and btrees in schema "s3" +plan_to_remove_relation_file('db1', 's3.t1'); +plan_to_corrupt_first_page('db1', 's3.t2'); + +plan_to_remove_relation_file('db1', 's3.t1_mv'); +plan_to_remove_relation_file('db1', 's3.p1_1'); + +plan_to_corrupt_first_page('db1', 's3.t2_mv'); +plan_to_corrupt_first_page('db1', 's3.p2_1'); + +plan_to_remove_relation_file('db1', 's3.t1_btree'); +plan_to_corrupt_first_page('db1', 's3.t2_btree'); + +# Corrupt toast table, partitions, and materialized views in schema "s4" +plan_to_remove_toast_file('db1', 's4.t2'); + +# Corrupt all other object types in schema "s5". We don't have amcheck support +# for these types, but we check that their corruption does not trigger any +# errors in pg_amcheck +plan_to_remove_relation_file('db1', 's5.seq1'); +plan_to_remove_relation_file('db1', 's5.t1_hash'); +plan_to_remove_relation_file('db1', 's5.t1_gist'); +plan_to_remove_relation_file('db1', 's5.t1_gin'); +plan_to_remove_relation_file('db1', 's5.t1_brin'); +plan_to_remove_relation_file('db1', 's5.t1_spgist'); + +plan_to_corrupt_first_page('db1', 's5.seq2'); +plan_to_corrupt_first_page('db1', 's5.t2_hash'); +plan_to_corrupt_first_page('db1', 's5.t2_gist'); +plan_to_corrupt_first_page('db1', 's5.t2_gin'); +plan_to_corrupt_first_page('db1', 's5.t2_brin'); +plan_to_corrupt_first_page('db1', 's5.t2_spgist'); + + +# Database 'db2' corruptions +# +plan_to_remove_relation_file('db2', 's1.t1'); +plan_to_remove_relation_file('db2', 's1.t1_btree'); + + +# Leave 'db3' uncorrupted +# + +# Standard first arguments to TestLib functions +my @cmd = ('pg_amcheck', '-p', $port); + +# Regular expressions to match various expected output +my $no_output_re = qr/^$/; +my $line_pointer_corruption_re = qr/line pointer/; +my $missing_file_re = qr/could not open file ".*": No such file or directory/; +my $index_missing_relation_fork_re = + qr/index ".*" lacks a main relation fork/; + +# We have created test databases with tables populated with data, but have not +# yet corrupted anything. As such, we expect no corruption and verify that +# none is reported +# +$node->command_checks_all([ @cmd, '-d', 'db1', '-d', 'db2', '-d', 'db3' ], + 0, [$no_output_re], [$no_output_re], 'pg_amcheck prior to corruption'); + +# Perform the corruptions we planned above using only a single database restart. +# +perform_all_corruptions(); + + +# Checking databases with amcheck installed and corrupt relations, pg_amcheck +# command itself should return exit status = 2, because tables and indexes are +# corrupt, not exit status = 1, which would mean the pg_amcheck command itself +# failed. Corruption messages should go to stdout, and nothing to stderr. +# +$node->command_checks_all( + [ @cmd, 'db1' ], + 2, + [ + $index_missing_relation_fork_re, $line_pointer_corruption_re, + $missing_file_re, + ], + [$no_output_re], + 'pg_amcheck all schemas, tables and indexes in database db1'); + +$node->command_checks_all( + [ @cmd, '-d', 'db1', '-d', 'db2', '-d', 'db3' ], + 2, + [ + $index_missing_relation_fork_re, $line_pointer_corruption_re, + $missing_file_re, + ], + [$no_output_re], + 'pg_amcheck all schemas, tables and indexes in databases db1, db2, and db3' +); + +# Scans of indexes in s1 should detect the specific corruption that we created +# above. For missing relation forks, we know what the error message looks +# like. For corrupted index pages, the error might vary depending on how the +# page was formatted on disk, including variations due to alignment differences +# between platforms, so we accept any non-empty error message. +# +# If we don't limit the check to databases with amcheck installed, we expect +# complaint on stderr, but otherwise stderr should be quiet. +# +$node->command_checks_all( + [ @cmd, '--all', '-s', 's1', '-i', 't1_btree' ], + 2, + [$index_missing_relation_fork_re], + [ + qr/pg_amcheck: warning: skipping database "postgres": amcheck is not installed/ + ], + 'pg_amcheck index s1.t1_btree reports missing main relation fork'); + +$node->command_checks_all( + [ @cmd, '-d', 'db1', '-s', 's1', '-i', 't2_btree' ], + 2, + [qr/.+/], # Any non-empty error message is acceptable + [$no_output_re], + 'pg_amcheck index s1.s2 reports index corruption'); + +# Checking db1.s1 with indexes excluded should show no corruptions because we +# did not corrupt any tables in db1.s1. Verify that both stdout and stderr +# are quiet. +# +$node->command_checks_all( + [ @cmd, '-t', 's1.*', '--no-dependent-indexes', 'db1' ], + 0, [$no_output_re], [$no_output_re], + 'pg_amcheck of db1.s1 excluding indexes'); + +# Checking db2.s1 should show table corruptions if indexes are excluded +# +$node->command_checks_all( + [ @cmd, '-t', 's1.*', '--no-dependent-indexes', 'db2' ], + 2, [$missing_file_re], [$no_output_re], + 'pg_amcheck of db2.s1 excluding indexes'); + +# In schema db1.s3, the tables and indexes are both corrupt. We should see +# corruption messages on stdout, and nothing on stderr. +# +$node->command_checks_all( + [ @cmd, '-s', 's3', 'db1' ], + 2, + [ + $index_missing_relation_fork_re, $line_pointer_corruption_re, + $missing_file_re, + ], + [$no_output_re], + 'pg_amcheck schema s3 reports table and index errors'); + +# In schema db1.s4, only toast tables are corrupt. Check that under default +# options the toast corruption is reported, but when excluding toast we get no +# error reports. +$node->command_checks_all([ @cmd, '-s', 's4', 'db1' ], + 2, [$missing_file_re], [$no_output_re], + 'pg_amcheck in schema s4 reports toast corruption'); + +$node->command_checks_all( + [ + @cmd, '--no-dependent-toast', '--exclude-toast-pointers', '-s', 's4', + 'db1' + ], + 0, + [$no_output_re], + [$no_output_re], + 'pg_amcheck in schema s4 excluding toast reports no corruption'); + +# Check that no corruption is reported in schema db1.s5 +$node->command_checks_all([ @cmd, '-s', 's5', 'db1' ], + 0, [$no_output_re], [$no_output_re], + 'pg_amcheck over schema s5 reports no corruption'); + +# In schema db1.s1, only indexes are corrupt. Verify that when we exclude +# the indexes, no corruption is reported about the schema. +# +$node->command_checks_all( + [ @cmd, '-s', 's1', '-I', 't1_btree', '-I', 't2_btree', 'db1' ], + 0, + [$no_output_re], + [$no_output_re], + 'pg_amcheck over schema s1 with corrupt indexes excluded reports no corruption' +); + +# In schema db1.s1, only indexes are corrupt. Verify that when we provide only +# table inclusions, and disable index expansion, no corruption is reported +# about the schema. +# +$node->command_checks_all( + [ @cmd, '-t', 's1.*', '--no-dependent-indexes', 'db1' ], + 0, + [$no_output_re], + [$no_output_re], + 'pg_amcheck over schema s1 with all indexes excluded reports no corruption' +); + +# In schema db1.s2, only tables are corrupt. Verify that when we exclude those +# tables that no corruption is reported. +# +$node->command_checks_all( + [ @cmd, '-s', 's2', '-T', 't1', '-T', 't2', 'db1' ], + 0, + [$no_output_re], + [$no_output_re], + 'pg_amcheck over schema s2 with corrupt tables excluded reports no corruption' +); + +# Check errors about bad block range command line arguments. We use schema s5 +# to avoid getting messages about corrupt tables or indexes. +# +command_fails_like( + [ @cmd, '-s', 's5', '--startblock', 'junk', 'db1' ], + qr/invalid start block/, + 'pg_amcheck rejects garbage startblock'); + +command_fails_like( + [ @cmd, '-s', 's5', '--endblock', '1234junk', 'db1' ], + qr/invalid end block/, + 'pg_amcheck rejects garbage endblock'); + +command_fails_like( + [ @cmd, '-s', 's5', '--startblock', '5', '--endblock', '4', 'db1' ], + qr/end block precedes start block/, + 'pg_amcheck rejects invalid block range'); + +# Check bt_index_parent_check alternates. We don't create any index corruption +# that would behave differently under these modes, so just smoke test that the +# arguments are handled sensibly. +# +$node->command_checks_all( + [ @cmd, '-s', 's1', '-i', 't1_btree', '--parent-check', 'db1' ], + 2, + [$index_missing_relation_fork_re], + [$no_output_re], + 'pg_amcheck smoke test --parent-check'); + +$node->command_checks_all( + [ + @cmd, '-s', 's1', '-i', 't1_btree', '--heapallindexed', + '--rootdescend', 'db1' + ], + 2, + [$index_missing_relation_fork_re], + [$no_output_re], + 'pg_amcheck smoke test --heapallindexed --rootdescend'); + +$node->command_checks_all( + [ @cmd, '-d', 'db1', '-d', 'db2', '-d', 'db3', '-S', 's*' ], + 0, [$no_output_re], [$no_output_re], + 'pg_amcheck excluding all corrupt schemas'); diff --git a/src/bin/pg_amcheck/t/004_verify_heapam.pl b/src/bin/pg_amcheck/t/004_verify_heapam.pl new file mode 100644 index 0000000..b603efa --- /dev/null +++ b/src/bin/pg_amcheck/t/004_verify_heapam.pl @@ -0,0 +1,529 @@ + +# Copyright (c) 2021, PostgreSQL Global Development Group + +use strict; +use warnings; + +use PostgresNode; +use TestLib; + +use Test::More; + +# This regression test demonstrates that the pg_amcheck binary correctly +# identifies specific kinds of corruption within pages. To test this, we need +# a mechanism to create corrupt pages with predictable, repeatable corruption. +# The postgres backend cannot be expected to help us with this, as its design +# is not consistent with the goal of intentionally corrupting pages. +# +# Instead, we create a table to corrupt, and with careful consideration of how +# postgresql lays out heap pages, we seek to offsets within the page and +# overwrite deliberately chosen bytes with specific values calculated to +# corrupt the page in expected ways. We then verify that pg_amcheck reports +# the corruption, and that it runs without crashing. Note that the backend +# cannot simply be started to run queries against the corrupt table, as the +# backend will crash, at least for some of the corruption types we generate. +# +# Autovacuum potentially touching the table in the background makes the exact +# behavior of this test harder to reason about. We turn it off to keep things +# simpler. We use a "belt and suspenders" approach, turning it off for the +# system generally in postgresql.conf, and turning it off specifically for the +# test table. +# +# This test depends on the table being written to the heap file exactly as we +# expect it to be, so we take care to arrange the columns of the table, and +# insert rows of the table, that give predictable sizes and locations within +# the table page. +# +# The HeapTupleHeaderData has 23 bytes of fixed size fields before the variable +# length t_bits[] array. We have exactly 3 columns in the table, so natts = 3, +# t_bits is 1 byte long, and t_hoff = MAXALIGN(23 + 1) = 24. +# +# We're not too fussy about which datatypes we use for the test, but we do care +# about some specific properties. We'd like to test both fixed size and +# varlena types. We'd like some varlena data inline and some toasted. And +# we'd like the layout of the table such that the datums land at predictable +# offsets within the tuple. We choose a structure without padding on all +# supported architectures: +# +# a BIGINT +# b TEXT +# c TEXT +# +# We always insert a 7-ascii character string into field 'b', which with a +# 1-byte varlena header gives an 8 byte inline value. We always insert a long +# text string in field 'c', long enough to force toast storage. +# +# We choose to read and write binary copies of our table's tuples, using perl's +# pack() and unpack() functions. Perl uses a packing code system in which: +# +# l = "signed 32-bit Long", +# L = "Unsigned 32-bit Long", +# S = "Unsigned 16-bit Short", +# C = "Unsigned 8-bit Octet", +# +# Each tuple in our table has a layout as follows: +# +# xx xx xx xx t_xmin: xxxx offset = 0 L +# xx xx xx xx t_xmax: xxxx offset = 4 L +# xx xx xx xx t_field3: xxxx offset = 8 L +# xx xx bi_hi: xx offset = 12 S +# xx xx bi_lo: xx offset = 14 S +# xx xx ip_posid: xx offset = 16 S +# xx xx t_infomask2: xx offset = 18 S +# xx xx t_infomask: xx offset = 20 S +# xx t_hoff: x offset = 22 C +# xx t_bits: x offset = 23 C +# xx xx xx xx xx xx xx xx 'a': xxxxxxxx offset = 24 LL +# xx xx xx xx xx xx xx xx 'b': xxxxxxxx offset = 32 CCCCCCCC +# xx xx xx xx xx xx xx xx 'c': xxxxxxxx offset = 40 CCllLL +# xx xx xx xx xx xx xx xx : xxxxxxxx ...continued +# xx xx : xx ...continued +# +# We could choose to read and write columns 'b' and 'c' in other ways, but +# it is convenient enough to do it this way. We define packing code +# constants here, where they can be compared easily against the layout. + +use constant HEAPTUPLE_PACK_CODE => 'LLLSSSSSCCLLCCCCCCCCCCllLL'; +use constant HEAPTUPLE_PACK_LENGTH => 58; # Total size + +# Read a tuple of our table from a heap page. +# +# Takes an open filehandle to the heap file, and the offset of the tuple. +# +# Rather than returning the binary data from the file, unpacks the data into a +# perl hash with named fields. These fields exactly match the ones understood +# by write_tuple(), below. Returns a reference to this hash. +# +sub read_tuple +{ + my ($fh, $offset) = @_; + my ($buffer, %tup); + sysseek($fh, $offset, 0) + or BAIL_OUT("sysseek failed: $!"); + defined(sysread($fh, $buffer, HEAPTUPLE_PACK_LENGTH)) + or BAIL_OUT("sysread failed: $!"); + + @_ = unpack(HEAPTUPLE_PACK_CODE, $buffer); + %tup = ( + t_xmin => shift, + t_xmax => shift, + t_field3 => shift, + bi_hi => shift, + bi_lo => shift, + ip_posid => shift, + t_infomask2 => shift, + t_infomask => shift, + t_hoff => shift, + t_bits => shift, + a_1 => shift, + a_2 => shift, + b_header => shift, + b_body1 => shift, + b_body2 => shift, + b_body3 => shift, + b_body4 => shift, + b_body5 => shift, + b_body6 => shift, + b_body7 => shift, + c_va_header => shift, + c_va_vartag => shift, + c_va_rawsize => shift, + c_va_extinfo => shift, + c_va_valueid => shift, + c_va_toastrelid => shift); + # Stitch together the text for column 'b' + $tup{b} = join('', map { chr($tup{"b_body$_"}) } (1 .. 7)); + return \%tup; +} + +# Write a tuple of our table to a heap page. +# +# Takes an open filehandle to the heap file, the offset of the tuple, and a +# reference to a hash with the tuple values, as returned by read_tuple(). +# Writes the tuple fields from the hash into the heap file. +# +# The purpose of this function is to write a tuple back to disk with some +# subset of fields modified. The function does no error checking. Use +# cautiously. +# +sub write_tuple +{ + my ($fh, $offset, $tup) = @_; + my $buffer = pack( + HEAPTUPLE_PACK_CODE, + $tup->{t_xmin}, $tup->{t_xmax}, + $tup->{t_field3}, $tup->{bi_hi}, + $tup->{bi_lo}, $tup->{ip_posid}, + $tup->{t_infomask2}, $tup->{t_infomask}, + $tup->{t_hoff}, $tup->{t_bits}, + $tup->{a_1}, $tup->{a_2}, + $tup->{b_header}, $tup->{b_body1}, + $tup->{b_body2}, $tup->{b_body3}, + $tup->{b_body4}, $tup->{b_body5}, + $tup->{b_body6}, $tup->{b_body7}, + $tup->{c_va_header}, $tup->{c_va_vartag}, + $tup->{c_va_rawsize}, $tup->{c_va_extinfo}, + $tup->{c_va_valueid}, $tup->{c_va_toastrelid}); + sysseek($fh, $offset, 0) + or BAIL_OUT("sysseek failed: $!"); + defined(syswrite($fh, $buffer, HEAPTUPLE_PACK_LENGTH)) + or BAIL_OUT("syswrite failed: $!"); + return; +} + +# Set umask so test directories and files are created with default permissions +umask(0077); + +# Set up the node. Once we create and corrupt the table, +# autovacuum workers visiting the table could crash the backend. +# Disable autovacuum so that won't happen. +my $node = get_new_node('test'); +$node->init; +$node->append_conf('postgresql.conf', 'autovacuum=off'); + +# Start the node and load the extensions. We depend on both +# amcheck and pageinspect for this test. +$node->start; +my $port = $node->port; +my $pgdata = $node->data_dir; +$node->safe_psql('postgres', "CREATE EXTENSION amcheck"); +$node->safe_psql('postgres', "CREATE EXTENSION pageinspect"); + +# Get a non-zero datfrozenxid +$node->safe_psql('postgres', qq(VACUUM FREEZE)); + +# Create the test table with precisely the schema that our corruption function +# expects. +$node->safe_psql( + 'postgres', qq( + CREATE TABLE public.test (a BIGINT, b TEXT, c TEXT); + ALTER TABLE public.test SET (autovacuum_enabled=false); + ALTER TABLE public.test ALTER COLUMN c SET STORAGE EXTERNAL; + CREATE INDEX test_idx ON public.test(a, b); + )); + +# We want (0 < datfrozenxid < test.relfrozenxid). To achieve this, we freeze +# an otherwise unused table, public.junk, prior to inserting data and freezing +# public.test +$node->safe_psql( + 'postgres', qq( + CREATE TABLE public.junk AS SELECT 'junk'::TEXT AS junk_column; + ALTER TABLE public.junk SET (autovacuum_enabled=false); + VACUUM FREEZE public.junk + )); + +my $rel = $node->safe_psql('postgres', + qq(SELECT pg_relation_filepath('public.test'))); +my $relpath = "$pgdata/$rel"; + +# Insert data and freeze public.test +use constant ROWCOUNT => 16; +$node->safe_psql( + 'postgres', qq( + INSERT INTO public.test (a, b, c) + VALUES ( + x'DEADF9F9DEADF9F9'::bigint, + 'abcdefg', + repeat('w', 10000) + ); + VACUUM FREEZE public.test + )) for (1 .. ROWCOUNT); + +my $relfrozenxid = $node->safe_psql('postgres', + q(select relfrozenxid from pg_class where relname = 'test')); +my $datfrozenxid = $node->safe_psql('postgres', + q(select datfrozenxid from pg_database where datname = 'postgres')); + +# Sanity check that our 'test' table has a relfrozenxid newer than the +# datfrozenxid for the database, and that the datfrozenxid is greater than the +# first normal xid. We rely on these invariants in some of our tests. +if ($datfrozenxid <= 3 || $datfrozenxid >= $relfrozenxid) +{ + $node->clean_node; + plan skip_all => + "Xid thresholds not as expected: got datfrozenxid = $datfrozenxid, relfrozenxid = $relfrozenxid"; + exit; +} + +# Find where each of the tuples is located on the page. +my @lp_off; +for my $tup (0 .. ROWCOUNT - 1) +{ + push( + @lp_off, + $node->safe_psql( + 'postgres', qq( +select lp_off from heap_page_items(get_raw_page('test', 'main', 0)) + offset $tup limit 1))); +} + +# Sanity check that our 'test' table on disk layout matches expectations. If +# this is not so, we will have to skip the test until somebody updates the test +# to work on this platform. +$node->stop; +my $file; +open($file, '+<', $relpath) + or BAIL_OUT("open failed: $!"); +binmode $file; + +my $ENDIANNESS; +for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++) +{ + my $offnum = $tupidx + 1; # offnum is 1-based, not zero-based + my $offset = $lp_off[$tupidx]; + my $tup = read_tuple($file, $offset); + + # Sanity-check that the data appears on the page where we expect. + my $a_1 = $tup->{a_1}; + my $a_2 = $tup->{a_2}; + my $b = $tup->{b}; + if ($a_1 != 0xDEADF9F9 || $a_2 != 0xDEADF9F9 || $b ne 'abcdefg') + { + close($file); # ignore errors on close; we're exiting anyway + $node->clean_node; + plan skip_all => + sprintf( + "Page layout differs from our expectations: expected (%x, %x, \"%s\"), got (%x, %x, \"%s\")", + 0xDEADF9F9, 0xDEADF9F9, "abcdefg", $a_1, $a_2, $b); + exit; + } + + # Determine endianness of current platform from the 1-byte varlena header + $ENDIANNESS = $tup->{b_header} == 0x11 ? "little" : "big"; +} +close($file) + or BAIL_OUT("close failed: $!"); +$node->start; + +# Ok, Xids and page layout look ok. We can run corruption tests. +plan tests => 19; + +# Check that pg_amcheck runs against the uncorrupted table without error. +$node->command_ok( + [ 'pg_amcheck', '-p', $port, 'postgres' ], + 'pg_amcheck test table, prior to corruption'); + +# Check that pg_amcheck runs against the uncorrupted table and index without error. +$node->command_ok([ 'pg_amcheck', '-p', $port, 'postgres' ], + 'pg_amcheck test table and index, prior to corruption'); + +$node->stop; + +# Some #define constants from access/htup_details.h for use while corrupting. +use constant HEAP_HASNULL => 0x0001; +use constant HEAP_XMAX_LOCK_ONLY => 0x0080; +use constant HEAP_XMIN_COMMITTED => 0x0100; +use constant HEAP_XMIN_INVALID => 0x0200; +use constant HEAP_XMAX_COMMITTED => 0x0400; +use constant HEAP_XMAX_INVALID => 0x0800; +use constant HEAP_NATTS_MASK => 0x07FF; +use constant HEAP_XMAX_IS_MULTI => 0x1000; +use constant HEAP_KEYS_UPDATED => 0x2000; + +# Helper function to generate a regular expression matching the header we +# expect verify_heapam() to return given which fields we expect to be non-null. +sub header +{ + my ($blkno, $offnum, $attnum) = @_; + return + qr/heap table "postgres\.public\.test", block $blkno, offset $offnum, attribute $attnum:\s+/ms + if (defined $attnum); + return + qr/heap table "postgres\.public\.test", block $blkno, offset $offnum:\s+/ms + if (defined $offnum); + return qr/heap table "postgres\.public\.test", block $blkno:\s+/ms + if (defined $blkno); + return qr/heap table "postgres\.public\.test":\s+/ms; +} + +# Corrupt the tuples, one type of corruption per tuple. Some types of +# corruption cause verify_heapam to skip to the next tuple without +# performing any remaining checks, so we can't exercise the system properly if +# we focus all our corruption on a single tuple. +# +my @expected; +open($file, '+<', $relpath) + or BAIL_OUT("open failed: $!"); +binmode $file; + +for (my $tupidx = 0; $tupidx < ROWCOUNT; $tupidx++) +{ + my $offnum = $tupidx + 1; # offnum is 1-based, not zero-based + my $offset = $lp_off[$tupidx]; + my $tup = read_tuple($file, $offset); + + my $header = header(0, $offnum, undef); + if ($offnum == 1) + { + # Corruptly set xmin < relfrozenxid + my $xmin = $relfrozenxid - 1; + $tup->{t_xmin} = $xmin; + $tup->{t_infomask} &= ~HEAP_XMIN_COMMITTED; + $tup->{t_infomask} &= ~HEAP_XMIN_INVALID; + + # Expected corruption report + push @expected, + qr/${header}xmin $xmin precedes relation freeze threshold 0:\d+/; + } + if ($offnum == 2) + { + # Corruptly set xmin < datfrozenxid + my $xmin = 3; + $tup->{t_xmin} = $xmin; + $tup->{t_infomask} &= ~HEAP_XMIN_COMMITTED; + $tup->{t_infomask} &= ~HEAP_XMIN_INVALID; + + push @expected, + qr/${$header}xmin $xmin precedes oldest valid transaction ID 0:\d+/; + } + elsif ($offnum == 3) + { + # Corruptly set xmin < datfrozenxid, further back, noting circularity + # of xid comparison. For a new cluster with epoch = 0, the corrupt + # xmin will be interpreted as in the future + $tup->{t_xmin} = 4026531839; + $tup->{t_infomask} &= ~HEAP_XMIN_COMMITTED; + $tup->{t_infomask} &= ~HEAP_XMIN_INVALID; + + push @expected, + qr/${$header}xmin 4026531839 equals or exceeds next valid transaction ID 0:\d+/; + } + elsif ($offnum == 4) + { + # Corruptly set xmax < relminmxid; + $tup->{t_xmax} = 4026531839; + $tup->{t_infomask} &= ~HEAP_XMAX_INVALID; + + push @expected, + qr/${$header}xmax 4026531839 equals or exceeds next valid transaction ID 0:\d+/; + } + elsif ($offnum == 5) + { + # Corrupt the tuple t_hoff, but keep it aligned properly + $tup->{t_hoff} += 128; + + push @expected, + qr/${$header}data begins at offset 152 beyond the tuple length 58/, + qr/${$header}tuple data should begin at byte 24, but actually begins at byte 152 \(3 attributes, no nulls\)/; + } + elsif ($offnum == 6) + { + # Corrupt the tuple t_hoff, wrong alignment + $tup->{t_hoff} += 3; + + push @expected, + qr/${$header}tuple data should begin at byte 24, but actually begins at byte 27 \(3 attributes, no nulls\)/; + } + elsif ($offnum == 7) + { + # Corrupt the tuple t_hoff, underflow but correct alignment + $tup->{t_hoff} -= 8; + + push @expected, + qr/${$header}tuple data should begin at byte 24, but actually begins at byte 16 \(3 attributes, no nulls\)/; + } + elsif ($offnum == 8) + { + # Corrupt the tuple t_hoff, underflow and wrong alignment + $tup->{t_hoff} -= 3; + + push @expected, + qr/${$header}tuple data should begin at byte 24, but actually begins at byte 21 \(3 attributes, no nulls\)/; + } + elsif ($offnum == 9) + { + # Corrupt the tuple to look like it has lots of attributes, not just 3 + $tup->{t_infomask2} |= HEAP_NATTS_MASK; + + push @expected, + qr/${$header}number of attributes 2047 exceeds maximum expected for table 3/; + } + elsif ($offnum == 10) + { + # Corrupt the tuple to look like it has lots of attributes, some of + # them null. This falsely creates the impression that the t_bits + # array is longer than just one byte, but t_hoff still says otherwise. + $tup->{t_infomask} |= HEAP_HASNULL; + $tup->{t_infomask2} |= HEAP_NATTS_MASK; + $tup->{t_bits} = 0xAA; + + push @expected, + qr/${$header}tuple data should begin at byte 280, but actually begins at byte 24 \(2047 attributes, has nulls\)/; + } + elsif ($offnum == 11) + { + # Same as above, but this time t_hoff plays along + $tup->{t_infomask} |= HEAP_HASNULL; + $tup->{t_infomask2} |= (HEAP_NATTS_MASK & 0x40); + $tup->{t_bits} = 0xAA; + $tup->{t_hoff} = 32; + + push @expected, + qr/${$header}number of attributes 67 exceeds maximum expected for table 3/; + } + elsif ($offnum == 12) + { + # Overwrite column 'b' 1-byte varlena header and initial characters to + # look like a long 4-byte varlena + # + # On little endian machines, bytes ending in two zero bits (xxxxxx00 bytes) + # are 4-byte length word, aligned, uncompressed data (up to 1G). We set the + # high six bits to 111111 and the lower two bits to 00, then the next three + # bytes with 0xFF using 0xFCFFFFFF. + # + # On big endian machines, bytes starting in two zero bits (00xxxxxx bytes) + # are 4-byte length word, aligned, uncompressed data (up to 1G). We set the + # low six bits to 111111 and the high two bits to 00, then the next three + # bytes with 0xFF using 0x3FFFFFFF. + # + $tup->{b_header} = $ENDIANNESS eq 'little' ? 0xFC : 0x3F; + $tup->{b_body1} = 0xFF; + $tup->{b_body2} = 0xFF; + $tup->{b_body3} = 0xFF; + + $header = header(0, $offnum, 1); + push @expected, + qr/${header}attribute with length \d+ ends at offset \d+ beyond total tuple length \d+/; + } + elsif ($offnum == 13) + { + # Corrupt the bits in column 'c' toast pointer + $tup->{c_va_valueid} = 0xFFFFFFFF; + + $header = header(0, $offnum, 2); + push @expected, qr/${header}toast value \d+ not found in toast table/; + } + elsif ($offnum == 14) + { + # Set both HEAP_XMAX_COMMITTED and HEAP_XMAX_IS_MULTI + $tup->{t_infomask} |= HEAP_XMAX_COMMITTED; + $tup->{t_infomask} |= HEAP_XMAX_IS_MULTI; + $tup->{t_xmax} = 4; + + push @expected, + qr/${header}multitransaction ID 4 equals or exceeds next valid multitransaction ID 1/; + } + elsif ($offnum == 15) # Last offnum must equal ROWCOUNT + { + # Set both HEAP_XMAX_COMMITTED and HEAP_XMAX_IS_MULTI + $tup->{t_infomask} |= HEAP_XMAX_COMMITTED; + $tup->{t_infomask} |= HEAP_XMAX_IS_MULTI; + $tup->{t_xmax} = 4000000000; + + push @expected, + qr/${header}multitransaction ID 4000000000 precedes relation minimum multitransaction ID threshold 1/; + } + write_tuple($file, $offset, $tup); +} +close($file) + or BAIL_OUT("close failed: $!"); +$node->start; + +# Run pg_amcheck against the corrupt table with epoch=0, comparing actual +# corruption messages against the expected messages +$node->command_checks_all( + [ 'pg_amcheck', '--no-dependent-indexes', '-p', $port, 'postgres' ], + 2, [@expected], [], 'Expected corruption message output'); + +$node->teardown_node; +$node->clean_node; diff --git a/src/bin/pg_amcheck/t/005_opclass_damage.pl b/src/bin/pg_amcheck/t/005_opclass_damage.pl new file mode 100644 index 0000000..30be684 --- /dev/null +++ b/src/bin/pg_amcheck/t/005_opclass_damage.pl @@ -0,0 +1,59 @@ + +# Copyright (c) 2021, PostgreSQL Global Development Group + +# This regression test checks the behavior of the btree validation in the +# presence of breaking sort order changes. +# +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 5; + +my $node = get_new_node('test'); +$node->init; +$node->start; + +# Create a custom operator class and an index which uses it. +$node->safe_psql( + 'postgres', q( + CREATE EXTENSION amcheck; + + CREATE FUNCTION int4_asc_cmp (a int4, b int4) RETURNS int LANGUAGE sql AS $$ + SELECT CASE WHEN $1 = $2 THEN 0 WHEN $1 > $2 THEN 1 ELSE -1 END; $$; + + CREATE OPERATOR CLASS int4_fickle_ops FOR TYPE int4 USING btree AS + OPERATOR 1 < (int4, int4), OPERATOR 2 <= (int4, int4), + OPERATOR 3 = (int4, int4), OPERATOR 4 >= (int4, int4), + OPERATOR 5 > (int4, int4), FUNCTION 1 int4_asc_cmp(int4, int4); + + CREATE TABLE int4tbl (i int4); + INSERT INTO int4tbl (SELECT * FROM generate_series(1,1000) gs); + CREATE INDEX fickleidx ON int4tbl USING btree (i int4_fickle_ops); +)); + +# We have not yet broken the index, so we should get no corruption +$node->command_like( + [ 'pg_amcheck', '-p', $node->port, 'postgres' ], + qr/^$/, + 'pg_amcheck all schemas, tables and indexes reports no corruption'); + +# Change the operator class to use a function which sorts in a different +# order to corrupt the btree index +$node->safe_psql( + 'postgres', q( + CREATE FUNCTION int4_desc_cmp (int4, int4) RETURNS int LANGUAGE sql AS $$ + SELECT CASE WHEN $1 = $2 THEN 0 WHEN $1 > $2 THEN -1 ELSE 1 END; $$; + UPDATE pg_catalog.pg_amproc + SET amproc = 'int4_desc_cmp'::regproc + WHERE amproc = 'int4_asc_cmp'::regproc +)); + +# Index corruption should now be reported +$node->command_checks_all( + [ 'pg_amcheck', '-p', $node->port, 'postgres' ], + 2, + [qr/item order invariant violated for index "fickleidx"/], + [], + 'pg_amcheck all schemas, tables and indexes reports fickleidx corruption' +); |