Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-41942

CHECK TABLE EXTENDED is missing column length and BLOB length validation for the record

    XMLWordPrintable

Details

    Description

      CHECK TABLE t EXTENDED is supposed to be the thorough, "go read everything and verify it" check. User is expected to run after something risky like ALTER TABLE ... IMPORT TABLESP ACE with an externally-supplied .ibd/.cfg pair, specifically to
      confirm the imported data is sound.

      However, if the imported tablespace has a corrupted on-page column length
      (either an ordinary column's length prefix, or a BLOB's external-storage length reference), CHECK TABLE ... EXTENDED currently reports the table as OK.
      It does not decode or validate individual field lengths against the table's own
      column definitions, and it does not verify that a BLOB's claimed length actually
      matches what can be recovered from its stored pages. So a user who
      imports a corrupted tablespace and then runs CHECK TABLE ... EXTENDED as a
      safety check gets a false "all clear".

      --source include/have_innodb.inc
      --source include/have_innodb_16k.inc
       
      let MYSQLD_DATADIR = `SELECT @@datadir`;
       
      CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(800) NOT NULL) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
      INSERT INTO t1 VALUES (1, REPEAT('x',200));
       
      FLUSH TABLES t1 FOR EXPORT;
      --copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQL_TMP_DIR/t1.ibd
      --copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQL_TMP_DIR/t1.cfg
      UNLOCK TABLES;
      DROP TABLE t1;
       
      perl;
      use strict;
      $| = 1;
      use Fcntl qw(:DEFAULT :seek);
      do "$ENV{MTR_SUITE_DIR}/include/crc32.pl";
      do "$ENV{MTR_SUITE_DIR}/include/innodb-util.pl";
       
      my $file = "$ENV{MYSQL_TMP_DIR}/t1.ibd";
      sysopen(FILE, $file, O_RDWR) or die "Cannot open $file: $!";
      my $page_size = 16384;
      my $full_crc32 = get_full_crc32(\*FILE);
       
      # For this exact, fixed table (single row, PK a INT, DB_TRX_ID(6) +
      # DB_ROLL_PTR(7), then one NOT NULL VARCHAR(800) column, 16k pages,
      # ROW_FORMAT=DYNAMIC) the on-page layout is deterministic:
      #   - the clustered index root/leaf is page 3;
      #   - the sole user record sits at page offset 127;
      #   - column b's 2-byte length-prefix (no NULL bitmap, since NOT NULL)
      #     is the two bytes immediately before the record, at offsets 121
      #     (near byte) and 120 (far byte).
      my $page_no = 3;
      sysseek(FILE, $page_no * $page_size, SEEK_SET) or die;
      my $page;
      sysread(FILE, $page, $page_size) == $page_size or die;
       
      sub decode_len {
        my ($hi, $lo) = @_;
        return undef unless $hi & 0x80;
        my $len = (($hi << 8) | $lo);
        return $len & 0x3fff; # DATA_MASK
      }
       
      my $near_off = 121;
      my $hi = ord(substr($page, $near_off, 1));
      my $lo = ord(substr($page, $near_off - 1, 1));
      my $decoded = decode_len($hi, $lo);
      die "page layout does not match the hardcoded offset; decoded $decoded"
        unless defined $decoded && $decoded == 200;
       
      # Re-encode to claim 16000 bytes, instead of
      # the real 200, without changing the actual reserved on-page space
      # for this field's data
      my $bogus = 16000;
      my $x = ($bogus >> 8) & 0x3f;   # 6 bits -> near byte's low bits
      my $y = $bogus & 0xff;          # low 8 bits -> far byte
      my $near_byte = 0x80 | $x;
      my $far_byte = $y;
      die "sanity check failed"
        unless decode_len($near_byte, $far_byte) == $bogus;
       
      substr($page, $near_off, 1) = chr($near_byte);
      substr($page, $near_off - 1, 1) = chr($far_byte);
       
      $page = fix_page_crc($page, $full_crc32);
       
      sysseek(FILE, $page_no * $page_size, SEEK_SET) or die;
      syswrite(FILE, $page, $page_size) == $page_size or die;
      close(FILE) or die;
      EOF
       
      CREATE TABLE t1 (a INT PRIMARY KEY, b VARCHAR(800) NOT NULL) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
      ALTER TABLE t1 DISCARD TABLESPACE;
       
      --copy_file $MYSQL_TMP_DIR/t1.ibd $MYSQLD_DATADIR/test/t1.ibd
      --copy_file $MYSQL_TMP_DIR/t1.cfg $MYSQLD_DATADIR/test/t1.cfg
       
      ALTER TABLE t1 IMPORT TABLESPACE;
       
      CHECK TABLE t1 extended;  -- Doesn't report failure
       
      DROP TABLE t1;
      --remove_file $MYSQL_TMP_DIR/t1.ibd
      --remove_file $MYSQL_TMP_DIR/t1.cfg
      
      

      Attachments

        Activity

          People

            thiru Thirunarayanan Balathandayuthapani
            thiru Thirunarayanan Balathandayuthapani
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:

              Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.