#!/usr/bin/perl

BEGIN {
   die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
      unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
   unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};

use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use Data::Dumper;

use VersionParser;
use DuplicateKeyFinder;
use Quoter;
use TableParser;
use PerconaTest;

$Data::Dumper::Purity = 1;
$Data::Dumper::Terse = 1;

my $dk = new DuplicateKeyFinder();
my $q  = new Quoter();
my $tp = new TableParser(Quoter => $q);

my $sample = "t/lib/samples/dupekeys/";
my $dupes;
my $callback = sub {
   push @$dupes, $_[0];
};

my $opt = { mysql_version => VersionParser->new('4.1.0') };
my $ddl;
my $tbl;

isa_ok($dk, 'DuplicateKeyFinder');

$ddl   = load_file('t/lib/samples/one_key.sql');
$dupes = [];
my ($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
   ],
   'One key, no dupes'
);

$ddl   = load_file('t/lib/samples/dupe_key.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'          => 'a',
         'cols'         => [qw(a)],
         ddl            => 'KEY `a` (`a`),',
         'duplicate_of' => 'a_2',
         'duplicate_of_cols' => [qw(a b)],
         duplicate_of_ddl    => 'KEY `a_2` (`a`,`b`)',
         'reason'       => 'a is a left-prefix of a_2',
         dupe_type      => 'prefix',
      }
   ],
   'Two dupe keys on table dupe_key'
);

$ddl   = load_file('t/lib/samples/dupe_key_reversed.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'          => 'a',
         'cols'         => [qw(a)],
         ddl            => 'KEY `a` (`a`),',
         'duplicate_of' => 'a_2',
         'duplicate_of_cols' => [qw(a b)],
         duplicate_of_ddl    => 'KEY `a_2` (`a`,`b`),',
         'reason'       => 'a is a left-prefix of a_2',
         dupe_type      => 'prefix',
      }
   ],
   'Two dupe keys on table dupe_key in reverse'
);

# This test might fail if your system sorts a_3 before a_2, because the
# keys are sorted by columns, not name. If this happens, then a_3 will
# duplicate a_2.
$ddl   = load_file('t/lib/samples/dupe_keys_thrice.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'          => 'a_3',
         'cols'         => [qw(a b)],
         ddl            => 'KEY `a_3` (`a`,`b`)',
         'duplicate_of' => 'a_2',
         'duplicate_of_cols' => [qw(a b)],
         duplicate_of_ddl    => 'KEY `a_2` (`a`,`b`),',
         'reason'       => 'a_3 is a duplicate of a_2',
         dupe_type      => 'exact',
      },
      {
         'key'          => 'a',
         'cols'         => [qw(a)],
         ddl            => 'KEY `a` (`a`),',
         'duplicate_of' => 'a_2',
         'duplicate_of_cols' => [qw(a b)],
         duplicate_of_ddl    => 'KEY `a_2` (`a`,`b`),',
         'reason'       => 'a is a left-prefix of a_2',
         dupe_type      => 'prefix',
      },
   ],
   'Dupe keys only output once (may fail due to different sort order)'
);

$ddl   = load_file('t/lib/samples/nondupe_fulltext.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [],
   'No dupe keys b/c of fulltext'
);
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   ignore_structure => 1,
   callback         => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'          => 'a',
         'cols'         => [qw(a)],
         ddl            => 'KEY `a` (`a`),',
         'duplicate_of' => 'a_2',
         'duplicate_of_cols' => [qw(a b)],
         duplicate_of_ddl    => 'FULLTEXT KEY `a_2` (`a`,`b`),',
         'reason'       => 'a is a left-prefix of a_2',
         dupe_type      => 'prefix',
      },
   ],
   'Dupe keys when ignoring structure'
);

$ddl   = load_file('t/lib/samples/nondupe_fulltext_not_exact.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [],
   'No dupe keys b/c fulltext requires exact match (issue 10)'
);

$ddl   = load_file('t/lib/samples/dupe_fulltext_exact.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'          => 'ft_idx_a_b_2',
         'cols'         => [qw(a b)],
         ddl            => 'FULLTEXT KEY `ft_idx_a_b_2` (`a`,`b`)',
         'duplicate_of' => 'ft_idx_a_b_1',
         'duplicate_of_cols' => [qw(a b)],
         duplicate_of_ddl    => 'FULLTEXT KEY `ft_idx_a_b_1` (`a`,`b`),',
         'reason'       => 'ft_idx_a_b_2 is a duplicate of ft_idx_a_b_1',
         dupe_type      => 'exact',
      }
   ],
   'Dupe exact fulltext keys (issue 10)'
);

$ddl   = load_file('t/lib/samples/dupe_fulltext_reverse_order.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
     {
       cols => [
         'b',
         'a'
       ],
       ddl => 'FULLTEXT KEY `ft_idx_b_a` (`b`,`a`)',
       dupe_type => 'exact',
       duplicate_of => 'ft_idx_a_b',
       duplicate_of_cols => [
         'a',
         'b'
       ],
       duplicate_of_ddl => 'FULLTEXT KEY `ft_idx_a_b` (`a`,`b`),',
       key => 'ft_idx_b_a',
       reason => 'ft_idx_b_a is a duplicate of ft_idx_a_b'
     }
   ],
   'Dupe reverse order fulltext keys (issue 10)'
) or diag(Dumper($dupes));

$ddl   = load_file('t/lib/samples/dupe_key_unordered.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [],
   'No dupe keys because of order'
);
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   ignore_order => 1,
   callback     => $callback);
is_deeply(
   $dupes,
   [
     {
       cols => [
         'a',
         'b'
       ],
       ddl => 'KEY `a_2` (`a`,`b`),',
       dupe_type => 'exact',
       duplicate_of => 'a',
       duplicate_of_cols => [
         'b',
         'a'
       ],
       duplicate_of_ddl => 'KEY `a` (`b`,`a`),',
       key => 'a_2',
       reason => 'a_2 is a duplicate of a'
     }
   ], 
   'Two dupe keys when ignoring order'
) or diag(Dumper($dupes));

# #############################################################################
# Clustered key tests.
# #############################################################################
$ddl   = load_file('t/lib/samples/innodb_dupe.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);

is_deeply(
   $dupes,
   [],
   'No duplicate keys with ordinary options'
);
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered => 1,
   tbl_info  => { engine => 'InnoDB', ddl => $ddl },
   callback  => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'          => 'b',
         'cols'         => [qw(b a)],
         ddl            => 'KEY `b` (`b`,`a`)',
         'duplicate_of' => 'PRIMARY',
         'duplicate_of_cols' => [qw(a)],
         duplicate_of_ddl    => 'PRIMARY KEY  (`a`),',
         'reason'       => 'Key b ends with a prefix of the clustered index',
         dupe_type      => 'clustered',
         short_key      => '`b`',
      }
   ],
   'Duplicate keys with cluster option'
);

$ddl = load_file('t/lib/samples/dupe_if_it_were_innodb.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered => 1,
   tbl_info  => {engine    => 'MyISAM', ddl => $ddl},
   callback  => $callback);
is_deeply(
   $dupes,
   [],
   'No cluster-duplicate keys because not InnoDB'
);

# This table is a test case for an infinite loop I ran into while writing the
# cluster stuff
$ddl = load_file('t/lib/samples/mysql_db.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered => 1,
   tbl_info  => { engine    => 'InnoDB', ddl => $ddl },
   callback  => $callback);
is_deeply(
   $dupes,
   [],
   'No cluster-duplicate keys in mysql.db'
);

# #############################################################################
# Duplicate FOREIGN KEY tests.
# #############################################################################
$ddl   = load_file('t/lib/samples/dupe_fk_one.sql');
$dupes = [];
$dk->get_duplicate_fks(
   $tp->get_fks($ddl, {database => 'test'}),
   callback => $callback);
is_deeply(
   $dupes,
    [
      {
        cols => [
          'b',
          'a'
        ],
        ddl => 'CONSTRAINT `t1_ibfk_2` FOREIGN KEY (`b`, `a`) REFERENCES `t2` (`b`, `a`)',
        dupe_type => 'fk',
        duplicate_of => 't1_ibfk_1',
        duplicate_of_cols => [
          'a',
          'b'
        ],
        duplicate_of_ddl => 'CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`a`, `b`) REFERENCES `t2` (`a`, `b`)',
        key => 't1_ibfk_2',
        reason => 'FOREIGN KEY t1_ibfk_2 (`b`, `a`) REFERENCES `test`.`t2` (`b`, `a`) is a duplicate of FOREIGN KEY t1_ibfk_1 (`a`, `b`) REFERENCES `test`.`t2` (`a`, `b`)'
      }
    ],
   'Two duplicate foreign keys'
) or diag(Dumper($dupes));

$ddl   = load_file('t/lib/samples/sakila_film.sql');
$dupes = [];
$dk->get_duplicate_fks(
   $tp->get_fks($ddl, {database => 'sakila'}),
   callback => $callback);
is_deeply(
   $dupes,
   [],
   'No duplicate foreign keys in sakila_film.sql'
);

# #############################################################################
# Issue 9: mk-duplicate-key-checker should treat unique and FK indexes specially
# #############################################################################

$ddl   = load_file('t/lib/samples/issue_9-1.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [],
   'Unique and non-unique keys with common prefix not dupes (issue 9)'
);

$ddl   = load_file('t/lib/samples/issue_9-2.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [],
   'PRIMARY and non-unique keys with common prefix not dupes (issue 9)'
);

$ddl   = load_file('t/lib/samples/issue_9-3.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'          => 'j',
         'cols'         => [qw(a b)],
         ddl            => 'KEY `j` (`a`,`b`)',
         'duplicate_of' => 'i',
         'duplicate_of_cols' => [qw(a b)],
         duplicate_of_ddl    => 'UNIQUE KEY `i` (`a`,`b`),',
         'reason'       => 'j is a duplicate of i',
         dupe_type      => 'exact',
      }
   ],
   'Non-unique key dupes unique key with same col cover (issue 9)'
);

$ddl   = load_file('t/lib/samples/issue_9-4.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'          => 'j',
         'cols'         => [qw(a b)],
         ddl            => 'KEY `j` (`a`,`b`)',
         'duplicate_of' => 'PRIMARY',
         'duplicate_of_cols' => [qw(a b)],
         duplicate_of_ddl    => 'PRIMARY KEY  (`a`,`b`),',
         'reason'       => 'j is a duplicate of PRIMARY',
         dupe_type      => 'exact',
      }
   ],
   'Non-unique key dupes PRIMARY key same col cover (issue 9)'
);

$ddl   = load_file('t/lib/samples/issue_9-5.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [],
   'Two unique keys with common prefix are not dupes'
);

$ddl   = load_file('t/lib/samples/uppercase_names.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'               => 'A',
         'cols'              => [qw(A)],
         ddl                 => 'KEY `A` (`A`)',
         'duplicate_of'      => 'PRIMARY',
         'duplicate_of_cols' => [qw(A)],
         duplicate_of_ddl    => 'PRIMARY KEY  (`A`),',
         'reason'            => "A is a duplicate of PRIMARY",
         dupe_type      => 'exact',
      },
   ],
   'Finds duplicates OK on uppercase columns',
);

$ddl   = load_file('t/lib/samples/issue_9-7.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
         'key'               => 'ua_b',
         'cols'              => [qw(a b)],
         ddl                 => 'UNIQUE KEY `ua_b` (`a`,`b`),',
         'duplicate_of'      => 'a_b_c',
         'duplicate_of_cols' => [qw(a b c)],
         duplicate_of_ddl    => 'KEY `a_b_c` (`a`,`b`,`c`)',
         'reason'            => "Uniqueness of ua_b ignored because PRIMARY is a stronger constraint\nua_b is a left-prefix of a_b_c",
         dupe_type      => 'prefix',
      },
   ],
   'Redundantly unique key dupes normal key after unconstraining'
);

$ddl   = load_file('t/lib/samples/issue_9-6.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
      {
       'duplicate_of' => 'PRIMARY',
       'reason' => 'a is a left-prefix of PRIMARY',
       dupe_type      => 'prefix',
       'duplicate_of_cols' => [qw(a b)],
       duplicate_of_ddl    => 'PRIMARY KEY  (`a`,`b`),',
       'cols' => [qw(a)],
       'key'  => 'a',
       ddl    => 'KEY `a` (`a`),',
      },
      {
       'duplicate_of' => 'PRIMARY',
       'reason' => 'a_b is a duplicate of PRIMARY',
       dupe_type      => 'exact',
       'duplicate_of_cols' => [qw(a b)],
       duplicate_of_ddl    => 'PRIMARY KEY  (`a`,`b`),',
       'cols' => [qw(a b)],
       'key'  => 'a_b',
       ddl    => 'KEY `a_b` (`a`,`b`),',
      },
      {
        cols => [
          'a',
          'b'
        ],
        ddl => 'UNIQUE KEY `ua_b2` (`a`,`b`),',
        dupe_type => 'exact',
        duplicate_of => 'PRIMARY',
        duplicate_of_cols => [qw(a b)],
        duplicate_of_ddl => 'PRIMARY KEY  (`a`,`b`),',
        key => 'ua_b2',
        reason => 'Uniqueness of ua_b2 ignored because ua is a stronger constraint
ua_b2 is a duplicate of PRIMARY'
      },
      {
        cols => [
          'a',
          'b'
        ],
        ddl => 'UNIQUE KEY `ua_b` (`a`,`b`),',
        dupe_type => 'exact',
        duplicate_of => 'PRIMARY',
        duplicate_of_cols => [qw(a b)],
        duplicate_of_ddl => 'PRIMARY KEY  (`a`,`b`),',
        key => 'ua_b',
        reason => 'Uniqueness of ua_b ignored because ua is a stronger constraint
ua_b is a duplicate of PRIMARY'
      }
   ],
   'Very pathological case',
) or diag(Dumper($dupes));

# #############################################################################
# Issue 269: mk-duplicate-key-checker: Wrongly suggesting removing index
# #############################################################################
$ddl   = load_file('t/lib/samples/issue_269-1.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [
   ],
   'Keep stronger unique constraint that is prefix'
);

# #############################################################################
# Issue 331: mk-duplicate-key-checker crashes when printing column types
# #############################################################################
$ddl   = load_file('t/lib/samples/issue_331.sql');
$dupes = [];
$dk->get_duplicate_fks(
   $tp->get_fks($ddl, {database => 'test'}),
   callback => $callback);
is_deeply(
   $dupes,
    [
      {
        cols => [
          'id'
        ],
        ddl => 'CONSTRAINT `fk_2` FOREIGN KEY (`id`) REFERENCES `issue_331_t1` (`t1_id`)',
        dupe_type => 'fk',
        duplicate_of => 'fk_1',
        duplicate_of_cols => [
          'id'
        ],
        duplicate_of_ddl => 'CONSTRAINT `fk_1` FOREIGN KEY (`id`) REFERENCES `issue_331_t1` (`t1_id`)',
        key => 'fk_2',
        reason => 'FOREIGN KEY fk_2 (`id`) REFERENCES `test`.`issue_331_t1` (`t1_id`) is a duplicate of FOREIGN KEY fk_1 (`id`) REFERENCES `test`.`issue_331_t1` (`t1_id`)'
      }
    ],
   'fk col not in referencing table (issue 331)'
) or diag(Dumper($dupes));

# #############################################################################
# Issue 295: Enhance rules for clustered keys in mk-duplicate-key-checker
# #############################################################################
is(
   $dk->shorten_clustered_duplicate('`a`', '`b`,`a`'),
   '`b`',
   "shorten_clustered_duplicate('`a`', '`b`,`a`')"
);

is(
   $dk->shorten_clustered_duplicate('`a`', '`a`'),
   '`a`',
   "shorten_clustered_duplicate('`a`', '`a`')"
);

is(
   $dk->shorten_clustered_duplicate('`a`,`b`', '`c`,`a`,`b`'),
   '`c`',
   "shorten_clustered_duplicate('`a`,`b`', '`c`,`a`,`b`'),"
);

$ddl   = load_file('t/lib/samples/issue_295-1.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   callback => $callback);
is_deeply(
   $dupes,
   [],
   'Do not remove clustered key acting as primary key'
);

# #############################################################################
# Issue 904: Tables that confuse mk-duplicate-key-checker
# #############################################################################
$ddl   = load_file("$sample/issue-904-1.txt");
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered     => 1,
   tbl_info      => { engine => 'InnoDB', ddl => $ddl },
   callback      => $callback
);

is_deeply(
   $dupes,
   [],
   'Clustered key with multiple columns (issue 904 1)'
);

$ddl   = load_file("$sample/issue-904-2.txt");
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered     => 1,
   tbl_info      => { engine => 'InnoDB', ddl => $ddl },
   callback      => $callback
);

is_deeply(
   $dupes,
   [],
   'Clustered key with multiple columns (issue 904 2)'
);

# #############################################################################
# Issue 1004: mk-dupe-key-checker recommends dropping and re-adding same index
# #############################################################################
$ddl   = load_file("$sample/issue-1004.txt");
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered     => 1,
   tbl_info      => { engine => 'InnoDB', ddl => $ddl },
   callback      => $callback
);

is_deeply(
   $dupes,
   [],
   'Issue 1004'
);

# #############################################################################
# Issue 1192: DROP/ADD leaves structure unchanged
# #############################################################################
$ddl   = load_file("$sample/issue-1192.sql");
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered     => 1,
   tbl_info      => { engine => 'InnoDB', ddl => $ddl },
   callback      => $callback
);

is_deeply(
   $dupes,
   [{
      key               => 'a',
      cols              => ['a'],
      ddl               => 'KEY `a` (`a`),',
      reason            => 'a is a duplicate of PRIMARY',
      dupe_type         => 'exact',
      duplicate_of      => 'PRIMARY',
      duplicate_of_cols => ['a'],
      duplicate_of_ddl  => 'PRIMARY KEY (`a`),',
   }],
   'Issue 1192'
);


# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/894140
# #############################################################################
$ddl   = load_file('t/lib/samples/dupekeys/dupe-cluster-bug-894140.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered     => 1,
   callback      => $callback,
   tbl_info      => { engine => 'InnoDB', ddl => $ddl },
);

is_deeply(
   $dupes,
   [
     {
       cols              => [ 'row_id' ],
       ddl               => 'UNIQUE KEY `row_id` (`row_id`),',
       dupe_type         => 'exact',
       duplicate_of      => 'PRIMARY',
       duplicate_of_cols => [ 'row_id' ],
       duplicate_of_ddl  => 'PRIMARY KEY (`row_id`),',
       key               => 'row_id',
       reason            => "Uniqueness of row_id ignored because PRIMARY is a duplicate constraint\nrow_id is a duplicate of PRIMARY",
     },
     {
       cols              => [ 'player_id' ],
       ddl               => 'KEY `player_id_2` (`player_id`)',
       dupe_type         => 'exact',
       duplicate_of      => 'player_id',
       duplicate_of_cols => [ 'player_id' ],
       duplicate_of_ddl  => 'UNIQUE KEY `player_id` (`player_id`),',
       key               => 'player_id_2',
       reason            => 'player_id_2 is a duplicate of player_id',
     },
   ],
   'Finds duplicates OK on uppercase columns',
);

# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1214114
# #############################################################################
#$ddl   = load_file('t/lib/samples/dupekeys/prefix_bug_1214114.sql');
#$dupes = [];
#($keys, $ck) = $tp->get_keys($ddl, $opt);
#$dk->get_duplicate_keys(
#   $keys,
#   clustered_key => $ck,
#   clustered     => 1,
#   callback      => $callback,
#   tbl_info      => { engine => 'InnoDB', ddl => $ddl },
#);
#
#is_deeply(
#   $dupes,
#   [{
#      cols => ['b', 'id'],
#      ddl => 'KEY `b` (`b`,`id`)',
#      dupe_type => 'clustered',
#      duplicate_of => 'PRIMARY',
#      duplicate_of_cols => ['id'],
#      duplicate_of_ddl => 'PRIMARY KEY (`id`),',
#      key => 'b',
#      reason => 'Key b ends with a prefix of the clustered index',
#      short_key => '`b`',
#   }],
#   "Prefix bug 1214114"
#) or diag(Dumper($dupes));

# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1217013
 #############################################################################
$ddl   = load_file('t/lib/samples/dupekeys/simple_dupe_bug_1217013.sql');
$dupes = [];
($keys, $ck) = $tp->get_keys($ddl, $opt);
$dk->get_duplicate_keys(
   $keys,
   clustered_key => $ck,
   clustered     => 1,
   callback      => $callback,
   tbl_info      => { engine => 'InnoDB', ddl => $ddl },
);

is_deeply(
   $dupes,
   [{
      cols              => ['domain'],
      ddl               => 'UNIQUE KEY `domain` (`domain`),',
      dupe_type         => 'exact',
      duplicate_of      => 'unique_key_domain',
      duplicate_of_cols => ['domain'],
      duplicate_of_ddl  => 'UNIQUE KEY `unique_key_domain` (`domain`)',
      key               => 'domain',
      reason            => "Uniqueness of domain ignored because unique_key_domain is a duplicate constraint\ndomain is a duplicate of unique_key_domain",
   }],
   "Exact dupe uniques (bug 1217013)"
) or diag(Dumper($dupes));

# #############################################################################
# Done.
# #############################################################################
my $output = '';
{
   local *STDERR;
   open STDERR, '>', \$output;
   $dk->_d('Complete test coverage');
}
like(
   $output,
   qr/Complete test coverage/,
   '_d() works'
);
done_testing;
