Support amcheck of sequences
authorPeter Eisentraut <peter@eisentraut.org>
Tue, 28 Sep 2021 13:26:25 +0000 (15:26 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Tue, 28 Sep 2021 13:26:25 +0000 (15:26 +0200)
Sequences were left out of the list of relation kinds that
verify_heapam knew how to check, though it is fairly trivial to allow
them.  Doing that, and while at it, updating pg_amcheck to include
sequences in relations matched by table and relation patterns.

Author: Mark Dilger <mark.dilger@enterprisedb.com>
Discussion: https://www.postgresql.org/message-id/flat/81ad4757-92c1-4aa3-7bee-f609544837e3%40enterprisedb.com

contrib/amcheck/expected/check_heap.out
contrib/amcheck/t/001_verify_heapam.pl
contrib/amcheck/verify_heapam.c
doc/src/sgml/amcheck.sgml
doc/src/sgml/ref/pg_amcheck.sgml
src/bin/pg_amcheck/pg_amcheck.c

index ad3086d2aacdc65e0b00e5577bba3bbca9f8295b..c010361025de3a572c49ddd5668447705f800691 100644 (file)
@@ -180,8 +180,10 @@ CREATE SEQUENCE test_sequence;
 SELECT * FROM verify_heapam('test_sequence',
                            startblock := NULL,
                            endblock := NULL);
-ERROR:  cannot check relation "test_sequence"
-DETAIL:  This operation is not supported for sequences.
+ blkno | offnum | attnum | msg 
+-------+--------+--------+-----
+(0 rows)
+
 -- Check that foreign tables are rejected
 CREATE FOREIGN DATA WRAPPER dummy;
 CREATE SERVER dummy_server FOREIGN DATA WRAPPER dummy;
index 4f720a7ed03863effd4c4cca4e87a0253e4e8149..ba40f64b58146a6a1499ddfd740c89b409e319ca 100644 (file)
@@ -8,7 +8,7 @@ use PostgresNode;
 use TestLib;
 
 use Fcntl qw(:seek);
-use Test::More tests => 80;
+use Test::More tests => 272;
 
 my ($node, $result);
 
@@ -60,6 +60,22 @@ detects_no_corruption(
    "verify_heapam('test', skip := 'all-frozen')",
    "all-frozen corrupted table skipping all-frozen");
 
+#
+# Check a sequence with no corruption.  The current implementation of sequences
+# doesn't require its own test setup, since sequences are really just heap
+# tables under-the-hood.  To guard against future implementation changes made
+# without remembering to update verify_heapam, we create and exercise a
+# sequence, checking along the way that it passes corruption checks.
+#
+fresh_test_sequence('test_seq');
+check_all_options_uncorrupted('test_seq', 'plain');
+advance_test_sequence('test_seq');
+check_all_options_uncorrupted('test_seq', 'plain');
+set_test_sequence('test_seq');
+check_all_options_uncorrupted('test_seq', 'plain');
+reset_test_sequence('test_seq');
+check_all_options_uncorrupted('test_seq', 'plain');
+
 # Returns the filesystem path for the named relation.
 sub relation_filepath
 {
@@ -110,6 +126,56 @@ sub fresh_test_table
    ));
 }
 
+# Create a test sequence of the given name.
+sub fresh_test_sequence
+{
+   my ($seqname) = @_;
+
+   return $node->safe_psql(
+       'postgres', qq(
+       DROP SEQUENCE IF EXISTS $seqname CASCADE;
+       CREATE SEQUENCE $seqname
+           INCREMENT BY 13
+           MINVALUE 17
+           START WITH 23;
+       SELECT nextval('$seqname');
+       SELECT setval('$seqname', currval('$seqname') + nextval('$seqname'));
+   ));
+}
+
+# Call SQL functions to increment the sequence
+sub advance_test_sequence
+{
+   my ($seqname) = @_;
+
+   return $node->safe_psql(
+       'postgres', qq(
+       SELECT nextval('$seqname');
+   ));
+}
+
+# Call SQL functions to set the sequence
+sub set_test_sequence
+{
+   my ($seqname) = @_;
+
+   return $node->safe_psql(
+       'postgres', qq(
+       SELECT setval('$seqname', 102);
+   ));
+}
+
+# Call SQL functions to reset the sequence
+sub reset_test_sequence
+{
+   my ($seqname) = @_;
+
+   return $node->safe_psql(
+       'postgres', qq(
+       ALTER SEQUENCE $seqname RESTART WITH 51
+   ));
+}
+
 # Stops the test node, corrupts the first page of the named relation, and
 # restarts the node.
 sub corrupt_first_page
index 173f99d787099d18c1ea1da8c189f3c687636cc9..91ef09a8ca8c4023f3f8ea940b4b5552167fb6c9 100644 (file)
@@ -305,14 +305,20 @@ verify_heapam(PG_FUNCTION_ARGS)
     */
    if (ctx.rel->rd_rel->relkind != RELKIND_RELATION &&
        ctx.rel->rd_rel->relkind != RELKIND_MATVIEW &&
-       ctx.rel->rd_rel->relkind != RELKIND_TOASTVALUE)
+       ctx.rel->rd_rel->relkind != RELKIND_TOASTVALUE &&
+       ctx.rel->rd_rel->relkind != RELKIND_SEQUENCE)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cannot check relation \"%s\"",
                        RelationGetRelationName(ctx.rel)),
                 errdetail_relkind_not_supported(ctx.rel->rd_rel->relkind)));
 
-   if (ctx.rel->rd_rel->relam != HEAP_TABLE_AM_OID)
+   /*
+    * Sequences always use heap AM, but they don't show that in the catalogs.
+    * Other relkinds might be using a different AM, so check.
+    */
+   if (ctx.rel->rd_rel->relkind != RELKIND_SEQUENCE &&
+       ctx.rel->rd_rel->relam != HEAP_TABLE_AM_OID)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("only heap AM is supported")));
index c570690b59c5783295143f83f6ea00c99e5c0b4f..11d1eb5af234a2b31a6cbaab955b4ee52eac8119 100644 (file)
@@ -220,10 +220,10 @@ SET client_min_messages = DEBUG1;
     </term>
     <listitem>
      <para>
-      Checks a table for structural corruption, where pages in the relation
-      contain data that is invalidly formatted, and for logical corruption,
-      where pages are structurally valid but inconsistent with the rest of the
-      database cluster.
+      Checks a table, sequence, or materialized view for structural corruption,
+      where pages in the relation contain data that is invalidly formatted, and
+      for logical corruption, where pages are structurally valid but
+      inconsistent with the rest of the database cluster.
      </para>
      <para>
       The following optional arguments are recognized:
index d00c48d0e7911c141bf69bea536b59eaf1d05bfe..1fd0ecd9114b5cb7e7449d18c34b92f3cabeb205 100644 (file)
@@ -41,8 +41,9 @@ PostgreSQL documentation
   </para>
 
   <para>
-   Only table relations and btree indexes are currently supported.  Other
-   relation types are silently skipped.
+   Only ordinary and toast table relations, materialized views, sequences, and
+   btree indexes are currently supported.  Other relation types are silently
+   skipped.
   </para>
 
   <para>
@@ -124,7 +125,7 @@ PostgreSQL documentation
       </para>
       <para>
        This is similar to the <option>--relation</option> option, except that
-       it applies only to indexes, not tables.
+       it applies only to indexes, not to other relation types.
       </para>
      </listitem>
     </varlistentry>
@@ -140,7 +141,7 @@ PostgreSQL documentation
       </para>
       <para>
        This is similar to the <option>--exclude-relation</option> option,
-       except that it applies only to indexes, not tables.
+       except that it applies only to indexes, not other relation types.
       </para>
      </listitem>
     </varlistentry>
@@ -236,7 +237,8 @@ PostgreSQL documentation
       </para>
       <para>
        This is similar to the <option>--relation</option> option, except that
-       it applies only to tables, not indexes.
+       it applies only to tables, materialized views, and sequences, not to
+       indexes.
       </para>
      </listitem>
     </varlistentry>
@@ -252,7 +254,8 @@ PostgreSQL documentation
       </para>
       <para>
        This is similar to the <option>--exclude-relation</option> option,
-       except that it applies only to tables, not indexes.
+       except that it applies only to tables, materialized views, and
+       sequences, not to indexes.
       </para>
      </listitem>
     </varlistentry>
index 9b6ab24810645e7258986edecc4201e8cf114425..ec04b977de0424fc970b2e7e63ab3676a4f4dab2 100644 (file)
@@ -1910,14 +1910,14 @@ compile_relation_list_one_db(PGconn *conn, SimplePtrList *relations,
    if (opts.allrel)
        appendPQExpBuffer(&sql,
                          " AND c.relam = %u "
-                         "AND c.relkind IN ('r', 'm', 't') "
+                         "AND c.relkind IN ('r', 'S', '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 "
+                         "AND c.relkind IN ('r', 'S', 'm', 't', 'i') "
+                         "AND ((c.relam = %u AND c.relkind IN ('r', 'S', 'm', 't')) OR "
                          "(c.relam = %u AND c.relkind = 'i'))",
                          HEAP_TABLE_AM_OID, BTREE_AM_OID,
                          HEAP_TABLE_AM_OID, BTREE_AM_OID);