diff -Nru pg-catcheck-1.1.0/debian/changelog pg-catcheck-1.2.0/debian/changelog --- pg-catcheck-1.1.0/debian/changelog 2020-04-07 17:39:53.000000000 +0000 +++ pg-catcheck-1.2.0/debian/changelog 2020-10-20 10:28:29.000000000 +0000 @@ -1,3 +1,27 @@ +pg-catcheck (1.2.0-1) unstable; urgency=medium + + * Team upload. + * New upstream version. + + -- Christoph Berg Tue, 20 Oct 2020 12:28:29 +0200 + +pg-catcheck (1.1.0-3) unstable; urgency=low + + * Team upload. + + [ Debian Janitor ] + * Set debhelper-compat version in Build-Depends. + * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository, + Repository-Browse. + + [ Christoph Berg ] + * Upload for PostgreSQL 13. + * Use dh --with pgxs. + * R³: no. + * DH 13. + + -- Christoph Berg Mon, 19 Oct 2020 10:30:08 +0200 + pg-catcheck (1.1.0-2) unstable; urgency=medium * Team upload. diff -Nru pg-catcheck-1.1.0/debian/compat pg-catcheck-1.2.0/debian/compat --- pg-catcheck-1.1.0/debian/compat 2020-04-07 17:07:42.000000000 +0000 +++ pg-catcheck-1.2.0/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -12 diff -Nru pg-catcheck-1.1.0/debian/control pg-catcheck-1.2.0/debian/control --- pg-catcheck-1.1.0/debian/control 2020-04-07 17:09:52.000000000 +0000 +++ pg-catcheck-1.2.0/debian/control 2020-10-19 08:47:45.000000000 +0000 @@ -4,16 +4,17 @@ Maintainer: Debian PostgreSQL Maintainers Uploaders: Michael Banck Build-Depends: - debhelper (>= 12), - postgresql-server-dev-all (>= 153~) -Standards-Version: 4.1.5 + debhelper-compat (= 13), + postgresql-all (>= 217~) +Standards-Version: 4.5.0 +Rules-Requires-Root: no Vcs-Browser: https://salsa.debian.org/postgresql/pg-catcheck Vcs-Git: https://salsa.debian.org/postgresql/pg-catcheck.git Homepage: https://github.com/EnterpriseDB/pg_catcheck/ -Package: postgresql-12-pg-catcheck +Package: postgresql-13-pg-catcheck Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, postgresql-12 +Depends: ${misc:Depends}, ${shlibs:Depends}, postgresql-13 Description: Postgres system catalog checker PostgreSQL stores the metadata for SQL objects such as tables and functions using special tables called system catalog tables. pg_catcheck is a simple diff -Nru pg-catcheck-1.1.0/debian/control.in pg-catcheck-1.2.0/debian/control.in --- pg-catcheck-1.1.0/debian/control.in 2020-04-07 17:07:42.000000000 +0000 +++ pg-catcheck-1.2.0/debian/control.in 2020-10-19 08:47:45.000000000 +0000 @@ -4,9 +4,10 @@ Maintainer: Debian PostgreSQL Maintainers Uploaders: Michael Banck Build-Depends: - debhelper (>= 12), - postgresql-server-dev-all (>= 153~) -Standards-Version: 4.1.5 + debhelper-compat (= 13), + postgresql-all (>= 217~) +Standards-Version: 4.5.0 +Rules-Requires-Root: no Vcs-Browser: https://salsa.debian.org/postgresql/pg-catcheck Vcs-Git: https://salsa.debian.org/postgresql/pg-catcheck.git Homepage: https://github.com/EnterpriseDB/pg_catcheck/ diff -Nru pg-catcheck-1.1.0/debian/rules pg-catcheck-1.2.0/debian/rules --- pg-catcheck-1.1.0/debian/rules 2020-04-07 17:07:42.000000000 +0000 +++ pg-catcheck-1.2.0/debian/rules 2020-10-19 08:37:50.000000000 +0000 @@ -1,20 +1,16 @@ #!/usr/bin/make -f -include /usr/share/postgresql-common/pgxs_debian_control.mk - override_dh_auto_build: +pg_buildext build build-%v $(MAKE) man -override_dh_auto_install: - +pg_buildext install build-%v postgresql-%v-pg-catcheck - override_dh_installdocs: dh_installdocs --all README.* -override_dh_auto_clean: - $(MAKE) clean - +pg_buildext clean build-%v +override_dh_pgxs_test: + for v in $(shell pg_buildext supported-versions); do \ + pg_virtualenv -v $$v debian/postgresql-$$v-pg-catcheck/usr/lib/postgresql/$$v/bin/pg_catcheck -v; \ + done %: - dh $@ + dh $@ --with pgxs diff -Nru pg-catcheck-1.1.0/debian/upstream/metadata pg-catcheck-1.2.0/debian/upstream/metadata --- pg-catcheck-1.1.0/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ pg-catcheck-1.2.0/debian/upstream/metadata 2020-10-19 08:28:23.000000000 +0000 @@ -0,0 +1,5 @@ +--- +Bug-Database: https://github.com/EnterpriseDB/pg_catcheck/issues +Bug-Submit: https://github.com/EnterpriseDB/pg_catcheck/issues/new +Repository: https://github.com/EnterpriseDB/pg_catcheck.git +Repository-Browse: https://github.com/EnterpriseDB/pg_catcheck diff -Nru pg-catcheck-1.1.0/definitions.c pg-catcheck-1.2.0/definitions.c --- pg-catcheck-1.1.0/definitions.c 2017-07-07 15:22:23.000000000 +0000 +++ pg-catcheck-1.2.0/definitions.c 2020-06-12 13:52:56.000000000 +0000 @@ -129,6 +129,12 @@ {CHECK_OID_REFERENCE, false, "pg_database"}; struct pg_catalog_check_oid check_subscription_oid = {CHECK_OID_REFERENCE, false, "pg_subscription"}; +struct pg_catalog_check_oid check_redaction_policy_oid = +{CHECK_OID_REFERENCE, false, "edb_redaction_policy"}; +struct pg_catalog_check_oid check_statistic_ext_oid = +{CHECK_OID_REFERENCE, false, "pg_statistic_ext"}; +struct pg_catalog_check_oid check_trigger_optional_oid = +{CHECK_OID_REFERENCE, true, "pg_trigger"}; /* pg_catalog_table & pg_catalog_column */ struct pg_catalog_column pg_class_column[] = @@ -152,6 +158,7 @@ { /* pg_namespace */ {"oid", NULL, 0, 0, false, true, true}, + {"nspname", NULL, 0, 0, false, false, true}, {"nspowner", NULL, 0, 0, false, false, false, &check_authid_oid}, {"nspparent", NULL, 0, 0, true, false, false, &check_namespace_optional_oid}, {"nspobjecttype", NULL, 90200, 0, true, false, false, &check_type_optional_oid}, @@ -258,6 +265,7 @@ {"conppeqop", NULL, 0, 0, false, false, false, &check_operator_oid_array}, {"conffeqop", NULL, 0, 0, false, false, false, &check_operator_oid_array}, {"conexclop", NULL, 90000, 0, false, false, false, &check_operator_oid_array}, + {"conparentid", NULL, 110000, 0, false, false, false, &check_constraint_optional_oid}, {NULL} }; @@ -313,8 +321,10 @@ { /* pg_trigger */ {"oid", NULL, 0, 0, false, true, true}, + {"tgpackageoid", NULL, 120000, 0, true, false, false, &check_namespace_optional_oid}, + {"tgparentid", NULL, 130000, 0, false, false, false, &check_trigger_optional_oid}, {"tgrelid", NULL, 0, 0, false, false, false, &check_class_oid}, - {"tgfoid", NULL, 0, 0, false, false, false, &check_proc_oid}, + {"tgfoid", NULL, 0, 0, false, false, false, &check_proc_optional_oid}, {"tgconstrrelid", NULL, 0, 0, false, false, false, &check_class_optional_oid}, {"tgconstrindid", NULL, 90000, 0, false, false, false, &check_index_optional_oid}, {"tgconstraint", NULL, 0, 0, false, false, false, &check_constraint_optional_oid}, @@ -581,6 +591,10 @@ {"staop2", NULL, 0, 0, false, false, false, &check_operator_optional_oid}, {"staop3", NULL, 0, 0, false, false, false, &check_operator_optional_oid}, {"staop4", NULL, 0, 0, false, false, false, &check_operator_optional_oid}, + {"stacoll1", NULL, 120000, 0, false, false, false, &check_collation_optional_oid}, + {"stacoll2", NULL, 120000, 0, false, false, false, &check_collation_optional_oid}, + {"stacoll3", NULL, 120000, 0, false, false, false, &check_collation_optional_oid}, + {"stacoll4", NULL, 120000, 0, false, false, false, &check_collation_optional_oid}, {NULL} }; @@ -795,6 +809,7 @@ { /* pg_partitioned_table */ {"partrelid", NULL, 100000, 0, false, true, true, &check_class_oid}, + {"partdefid", NULL, 110000, 0, false, false, false, &check_class_optional_oid}, {"partclass", NULL, 100000, 0, false, false, false, &check_opclass_oid_vector}, {"partcollation", NULL, 100000, 0, false, false, false, &check_collation_optional_oid_vector}, {NULL} @@ -849,6 +864,13 @@ {NULL} }; +struct pg_catalog_column pg_statistic_ext_data_column[] = +{ + /* pg_statistic_ext_data */ + {"stxoid", NULL, 120000, 0, false, true, true, &check_statistic_ext_oid}, + {NULL} +}; + struct pg_catalog_column pg_subscription_column[] = { /* pg_subscription */ @@ -877,6 +899,23 @@ {NULL} }; +struct pg_catalog_column edb_redaction_column[] = +{ + /* edb_redaction_column */ + {"oid", NULL, 110000, 0, true, true, true}, + {"rdpolicyid", NULL, 110000, 0, true, false, false, &check_redaction_policy_oid}, + {"rdrelid", NULL, 110000, 0, true, false, false, &check_class_oid}, + {NULL} +}; + +struct pg_catalog_column edb_redaction_policy_column[] = +{ + /* edb_redaction_policy */ + {"oid", NULL, 110000, 0, true, true, true}, + {"rdrelid", NULL, 110000, 0, true, false, false, &check_class_oid}, + {NULL} +}; + struct pg_catalog_table pg_catalog_tables[] = { {"pg_class", pg_class_column}, @@ -953,5 +992,8 @@ {"pg_subscription", pg_subscription_column}, {"pg_subscription_rel", pg_subscription_rel_column}, {"pg_transform", pg_transform_column}, + {"edb_redaction_column", edb_redaction_column}, + {"edb_redaction_policy", edb_redaction_policy_column}, + {"pg_statistic_ext_data", pg_statistic_ext_data_column}, {NULL} }; diff -Nru pg-catcheck-1.1.0/Makefile pg-catcheck-1.2.0/Makefile --- pg-catcheck-1.1.0/Makefile 2017-07-07 15:22:23.000000000 +0000 +++ pg-catcheck-1.2.0/Makefile 2020-06-12 13:52:56.000000000 +0000 @@ -3,7 +3,8 @@ PROGRAM = pg_catcheck OBJS = pg_catcheck.o check_attribute.o check_class.o check_depend.o \ - check_oids.o compat.o definitions.o log.o pgrhash.o + check_oids.o compat.o definitions.o log.o pgrhash.o \ + select_from_relations.o PG_CPPFLAGS = -I$(libpq_srcdir) PG_LIBS = $(libpq_pgport) $(PTHREAD_LIBS) diff -Nru pg-catcheck-1.1.0/pg_catcheck.c pg-catcheck-1.2.0/pg_catcheck.c --- pg-catcheck-1.1.0/pg_catcheck.c 2017-07-07 15:22:23.000000000 +0000 +++ pg-catcheck-1.2.0/pg_catcheck.c 2020-06-12 13:52:56.000000000 +0000 @@ -40,6 +40,7 @@ int remote_version; bool remote_is_edb; char *database_oid; +bool select_from_relations = false; #define MINIMUM_SUPPORTED_VERSION 80400 @@ -72,6 +73,7 @@ {"column", required_argument, NULL, 'c'}, {"quiet", no_argument, NULL, 'q'}, {"verbose", no_argument, NULL, 'v'}, + {"select-from-relations", no_argument, NULL, 105}, {"target-version", required_argument, NULL, 101}, {"enterprisedb", no_argument, NULL, 102}, {"postgresql", no_argument, NULL, 103}, @@ -158,6 +160,9 @@ remote_is_edb = false; detect_edb = false; break; + case 105: + select_from_relations = true; + break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); @@ -592,6 +597,10 @@ } } + /* Prepare for select_from_relations, if option been provided. */ + if (select_from_relations) + prepare_to_select_from_relations(); + /* * Second pass: allow individual checks to mark additional columns as * needed, and set ordering dependencies. @@ -734,6 +743,10 @@ /* Check the table. */ check_table(conn, best); } + + /* Check select-from-relations */ + if (select_from_relations) + perform_select_from_relations(conn); } /* @@ -1011,6 +1024,7 @@ printf(" -t, --table check only columns in the named tables\n"); printf(" -T, --exclude-table do NOT check the named tables\n"); printf(" -C, --exclude-column do NOT check the named columns\n"); + printf(" --select-from-relations execute the SELECT on relations in the database\n"); printf(" --target-version=VERSION assume specified target version\n"); printf(" --enterprisedb assume EnterpriseDB database\n"); printf(" --postgresql assume PostgreSQL database\n"); diff -Nru pg-catcheck-1.1.0/pg_catcheck.h pg-catcheck-1.2.0/pg_catcheck.h --- pg-catcheck-1.1.0/pg_catcheck.h 2017-07-07 15:22:23.000000000 +0000 +++ pg-catcheck-1.2.0/pg_catcheck.h 2020-06-12 13:52:56.000000000 +0000 @@ -144,6 +144,10 @@ extern void check_oid_reference(pg_catalog_table *tab, pg_catalog_column *tabcol, int rownum); +/* select_from_relations.c */ +extern void prepare_to_select_from_relations(void); +extern void perform_select_from_relations(PGconn *conn); + /* log.c */ typedef enum pgcc_severity { diff -Nru pg-catcheck-1.1.0/pg_catcheck.proj pg-catcheck-1.2.0/pg_catcheck.proj --- pg-catcheck-1.1.0/pg_catcheck.proj 2017-07-07 15:22:23.000000000 +0000 +++ pg-catcheck-1.2.0/pg_catcheck.proj 2020-06-12 13:52:56.000000000 +0000 @@ -63,6 +63,7 @@ + diff -Nru pg-catcheck-1.1.0/README.md pg-catcheck-1.2.0/README.md --- pg-catcheck-1.1.0/README.md 2017-07-07 15:22:23.000000000 +0000 +++ pg-catcheck-1.2.0/README.md 2020-06-12 13:52:56.000000000 +0000 @@ -78,6 +78,10 @@ not be attempted unless you are knowledgeable about how PostgreSQL uses these catalogs. +pg_catcheck also provides an option to run "SELECT * FROM table_name LIMIT 0" +on each table in the database, which will detect missing or inaccessible +relation files. The --select-from-relations option enables this check. + What is the license for pg_catcheck? Can I contribute? ======================================================= diff -Nru pg-catcheck-1.1.0/select_from_relations.c pg-catcheck-1.2.0/select_from_relations.c --- pg-catcheck-1.1.0/select_from_relations.c 1970-01-01 00:00:00.000000000 +0000 +++ pg-catcheck-1.2.0/select_from_relations.c 2020-06-12 13:52:56.000000000 +0000 @@ -0,0 +1,130 @@ +/*------------------------------------------------------------------------- + * + * select_from_relations.c + * + * Try to select from relations with storage. This will fail if the + * underlying files are absent or inaccessible. This is a little outside + * the general remit of this tool, which is to check the integrity of + * the system catalogs, but it seems like a useful addition. + * + *------------------------------------------------------------------------- + */ + +#include "postgres_fe.h" +#include "pg_catcheck.h" +#include "pqexpbuffer.h" + +/* + * Set up to check SELECT from relations. + */ +void +prepare_to_select_from_relations(void) +{ + pg_catalog_table *pg_class = find_table_by_name("pg_class"); + pg_catalog_table *pg_namespace = find_table_by_name("pg_namespace"); + + /* Flag tables that must be loaded for this check. */ + pg_class->needs_check = true; + pg_class->needs_load = true; + pg_namespace->needs_load = true; + pg_namespace->needs_check = true; + + /* Flag columns that must be loaded for this check. */ + find_column_by_name(pg_namespace, "nspname")->needed = true; + find_column_by_name(pg_class, "relname")->needed = true; + find_column_by_name(pg_class, "relnamespace")->needed = true; + find_column_by_name(pg_class, "relkind")->needed = true; +} + +/* + * Try a SELECT from each relation. + * + * We use SELECT 0 here to make it fast; we're just trying to verify + * that selecting data from the relation doesn't fail outright. + */ +void +perform_select_from_relations(PGconn *conn) +{ + PQExpBuffer query; + char *tablename, + *nspname, + *nspoid; + int rownum; + int ntups; + int oid_result_column; + int relname_result_column; + int relnamespace_result_column; + int relkind_result_column; + int nspname_result_column; + pg_catalog_table *pg_class = find_table_by_name("pg_class"); + pg_catalog_table *pg_namespace = find_table_by_name("pg_namespace"); + + /* + * If we weren't able to retrieve the table data for either table, then + * we can't run these checks. + */ + if (PQresultStatus(pg_class->data) != PGRES_TUPLES_OK || + PQresultStatus(pg_namespace->data) != PGRES_TUPLES_OK) + return; + + /* Locate the data we need. */ + ntups = PQntuples(pg_class->data); + oid_result_column = PQfnumber(pg_class->data, "oid"); + relname_result_column = PQfnumber(pg_class->data, "relname"); + relnamespace_result_column = PQfnumber(pg_class->data, "relnamespace"); + relkind_result_column = PQfnumber(pg_class->data, "relkind"); + nspname_result_column = PQfnumber(pg_namespace->data, "nspname"); + + query = createPQExpBuffer(); + + /* Loop over the rows and check them. */ + for (rownum = 0; rownum < ntups; ++rownum) + { + char relkind; + int nsp_rownum; + PGresult *qryres; + + /* Check plain tables, toast tables, and materialized views. */ + relkind = *(PQgetvalue(pg_class->data, rownum, relkind_result_column)); + if (relkind != 'r' && relkind != 't' && relkind != 'm') + continue; + + /* Get the table name and namespace OID from the pg_class */ + tablename = PQgetvalue(pg_class->data, rownum, relname_result_column); + nspoid = PQgetvalue(pg_class->data, rownum, relnamespace_result_column); + + /* + * Get the namespace name for the given namespace OID. Any errors here + * have already been reported, so we just emit a debug message here. + */ + nsp_rownum = pgrhash_get(pg_namespace->ht, &nspoid); + if (nsp_rownum == -1) + { + pgcc_log(PGCC_DEBUG, + "can't find schema name for select query for table with OID %s\n", + PQgetvalue(pg_class->data, rownum, oid_result_column)); + continue; + } + nspname = PQgetvalue(pg_namespace->data, nsp_rownum, nspname_result_column); + + /* Debug message. */ + pgcc_log(PGCC_DEBUG, "selecting from \"%s\".\"%s\"\n", nspname, tablename); + + /* Build up a query. */ + resetPQExpBuffer(query); + appendPQExpBuffer(query, "SELECT 1 FROM %s.%s LIMIT 0", + PQescapeIdentifier(conn, nspname, strlen(nspname)), + PQescapeIdentifier(conn, tablename, strlen(tablename))); + + /* Run the query. */ + qryres = PQexec(conn, query->data); + if (PQresultStatus(qryres) != PGRES_TUPLES_OK) + pgcc_log(PGCC_NOTICE, + "unable to query relation \"%s\".\"%s\": %s", + nspname, tablename, PQerrorMessage(conn)); + + /* Clean up. */ + PQclear(qryres); + } + destroyPQExpBuffer(query); +}