PT-1572 WIP

This commit is contained in:
Carlos Salguero
2018-07-27 22:16:02 -03:00
parent 909125faf9
commit ea4886ad9d
4 changed files with 130 additions and 3 deletions

View File

@@ -13262,6 +13262,10 @@ the values are converted to strings by the CONCAT() function, and MySQL chooses
the string representation. If you specify a value of 2, for example, then the
values 1.008 and 1.009 will be rounded to 1.01, and will checksum as equal.
=item --force-concat-enums
bla bla bla bla bla
=item --function
type: string

View File

@@ -134,14 +134,37 @@ sub new {
);
PTDEBUG && _d('Ascend params:', Dumper($asc));
# Check if enum fields items are sorted or not.
# If they are sorted we can skip adding CONCAT to improve the queries eficiency.
my $force_concat_enums = $o->has('force-concat-enums') && $o->get('force-concat-enums');
for my $index (@{$index_cols}) {
if ($tbl->{tbl_struct}->{type_for}->{$index} eq 'enum') {
if ($tbl->{tbl_struct}->{defs}->{$index} =~ m/enum\s*\((.*?)\)/) {
my @items = split(/,\s*/, $1);
my $sorted = 1; # Asume the items list is sorted to later check if this is true
for (my $i=1; $i < scalar(@items); $i++) {
if ($items[$i-1] gt $items[$i]) {
$sorted = 0;
last;
}
}
if (!$force_concat_enums && !$sorted) {
die "The index " . $index . " in table " . $tbl->{name} .
" has unsorted enum items.\nPlease read the documentation for the --force-concat-enums parameter\n";
}
}
}
}
# Make SQL statements, prepared on first call to next(). FROM and
# ORDER BY are the same for all statements. FORCE IDNEX and ORDER BY
# are needed to ensure deterministic nibbling.
my $from = "$tbl->{name} FORCE INDEX(`$index`)";
my $order_by = join(', ', map { $tbl->{tbl_struct}->{type_for}->{$_} eq 'enum'
my $order_by = join(', ', map { $tbl->{tbl_struct}->{type_for}->{$_} eq 'enum' && $force_concat_enums
? "CONCAT(".$q->quote($_).")" : $q->quote($_)} @{$index_cols});
my $order_by_dec = join(' DESC,', map { $tbl->{tbl_struct}->{type_for}->{$_} eq 'enum'
my $order_by_dec = join(' DESC,', map { $tbl->{tbl_struct}->{type_for}->{$_} eq 'enum' && $force_concat_enums
? "CONCAT(".$q->quote($_).")" : $q->quote($_)} @{$index_cols});
# The real first row in the table. Usually we start nibbling from

View File

@@ -38,6 +38,8 @@ my $dbh = $sb->get_dbh_for('master');
if ( !$dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
} else {
plan tests => 60;
}
my $q = new Quoter();
@@ -879,7 +881,7 @@ is_deeply(
# #############################################################################
diag(`/tmp/12345/use < $trunk/t/lib/samples/cardinality.sql >/dev/null`);
$dbh->do('analyze table bad_tables.inv');
$ni = make_nibble_iter(
db => 'cardb',
tbl => 't',
@@ -892,6 +894,56 @@ is(
"Use non-unique index with highest cardinality (bug 1199591)"
);
$sb->load_file('master', "t/lib/samples/NibbleIterator/enum_keys.sql");
$ni = undef;
eval {
$ni = make_nibble_iter(
db => 'test',
tbl => 't1',
argv => [qw(--databases test --chunk-size 3)],
);
};
like(
$EVAL_ERROR,
qr/The index f3 in table `test`.`t1` has unsorted enum items/,
"PT-1572 Die on unsorted enum items in index",
);
eval {
$ni = make_nibble_iter(
db => 'test',
tbl => 't1',
argv => [qw(--databases test --force-concat-enums --chunk-size 3)],
);
};
like(
$ni->{explain_first_lb_sql},
qr/ORDER BY `f1`, `f2`, CONCAT\(`f3`\)/,
"PT-1572 Use of CONCAT for unsorted ENUM field items without --",
);
eval {
$ni = make_nibble_iter(
db => 'test',
tbl => 't2',
argv => [qw(--databases test --chunk-size 3)],
);
};
is(
$EVAL_ERROR,
'',
"PT-1572 No errors on sorted enum items in index",
);
like(
$ni->{explain_first_lb_sql},
qr/ORDER BY `f1`, `f2`, `f3`/,
"PT-1572 Don't use CONCAT for sorted ENUM field items without --force-concat-enums",
);
# #############################################################################
# Done.
# #############################################################################
@@ -905,6 +957,7 @@ like(
qr/Complete test coverage/,
'_d() works'
);
$sb->wipe_clean($dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;

View File

@@ -0,0 +1,47 @@
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
USE test;
-- Don't change the comments. The enum word inside the comment is there to test the table parser
CREATE TABLE `test`.`t1` (
f1 DATE NOT NULL,
f2 INT(10) UNSIGNED NOT NULL,
f3 ENUM('c','a','b','d') NOT NULL DEFAULT 'c' COMMENT "unsorted enum items",
f4 INT(10) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`f1`,`f2`,`f3`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `t1` VALUES
('2018-07-27',165910161,'c',1375471152),
('2018-07-27',393713658,'d',1382302491),
('2018-07-27',472875023,'c',525456967),
('2018-07-27',543582931,'c',1657080267),
('2018-07-27',583532949,'d',280366509),
('2018-07-27',1396416465,'d',1252007743),
('2018-07-27',1705409249,'c',1714682759),
('2018-07-27',1801160058,'a',1022430181),
('2018-07-27',1898674299,'c',1310715836),
('2018-07-27',2011751560,'a',109015753);
CREATE TABLE `test`.`t2` (
f1 DATE NOT NULL,
f2 INT(10) UNSIGNED NOT NULL,
f3 ENUM('a','b','c','d') NOT NULL DEFAULT 'c' COMMENT "sorted enum items",
f4 INT(10) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`f1`,`f2`,`f3`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `t2` VALUES
('2018-07-27',165910161,'c',1375471152),
('2018-07-27',393713658,'d',1382302491),
('2018-07-27',472875023,'c',525456967),
('2018-07-27',543582931,'c',1657080267),
('2018-07-27',583532949,'d',280366509),
('2018-07-27',1396416465,'d',1252007743),
('2018-07-27',1705409249,'c',1714682759),
('2018-07-27',1801160058,'a',1022430181),
('2018-07-27',1898674299,'c',1310715836),
('2018-07-27',2011751560,'a',109015753);