Files
percona-toolkit/t/lib/QueryRewriter.t
Carlos Salguero 9d6508da5f PT-1900 pt-query-digest not hiding parameter properly sometimes when parameter=binary (#510)
* PT-1900 WIP

* Fixed quoted strings regexes

* PT-1900 Fixed query rewriter to properly handle quoted text

* Fixed merge conflicts with 3.x branch
2021-09-27 08:23:23 -03:00

1498 lines
43 KiB
Perl

#!/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 QueryRewriter;
use QueryParser;
use PerconaTest;
my $qp = new QueryParser();
my $qr = new QueryRewriter(QueryParser=>$qp);
# #############################################################################
# strip_comments()
# #############################################################################
is(
$qr->strip_comments("select \n--bar\n foo"),
"select \n\n foo",
'Removes one-line comments',
);
is(
$qr->strip_comments("select foo--bar\nfoo"),
"select foo\nfoo",
'Removes one-line comments without running them together',
);
is(
$qr->strip_comments("select foo -- bar"),
"select foo ",
'Removes one-line comments at end of line',
);
is(
$qr->strip_comments("select /*\nhello!*/ 1"),
'select 1',
'Stripped star comment',
);
is(
$qr->strip_comments('select /*!40101 hello*/ 1'),
'select /*!40101 hello*/ 1',
'Left version star comment',
);
# #############################################################################
# fingerprint()
# #############################################################################
is(
$qr->fingerprint(
q{UPDATE groups_search SET charter = ' -------3\'\' XXXXXXXXX.\n \n -----------------------------------------------------', show_in_list = 'Y' WHERE group_id='aaaaaaaa'}),
'update groups_search set charter = ?, show_in_list = ? where group_id=?',
'complex comments',
);
is(
$qr->fingerprint("SELECT /*!40001 SQL_NO_CACHE */ * FROM `film`"),
"mysqldump",
'Fingerprints all mysqldump SELECTs together',
);
is(
$qr->fingerprint("CALL foo(1, 2, 3)"),
"call foo",
'Fingerprints stored procedure calls specially',
);
is(
$qr->fingerprint('administrator command: Init DB'),
'administrator command: Init DB',
'Fingerprints admin commands as themselves',
);
is(
$qr->fingerprint(
q{REPLACE /*foo.bar:3/3*/ INTO checksum.checksum (db, tbl, }
.q{chunk, boundaries, this_cnt, this_crc) SELECT 'foo', 'bar', }
.q{2 AS chunk_num, '`id` >= 2166633', COUNT(*) AS cnt, }
.q{LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `id`, `created_by`, }
.q{`created_date`, `updated_by`, `updated_date`, `ppc_provider`, }
.q{`account_name`, `provider_account_id`, `campaign_name`, }
.q{`provider_campaign_id`, `adgroup_name`, `provider_adgroup_id`, }
.q{`provider_keyword_id`, `provider_ad_id`, `foo`, `reason`, }
.q{`foo_bar_bazz_id`, `foo_bar_baz`, CONCAT(ISNULL(`created_by`), }
.q{ISNULL(`created_date`), ISNULL(`updated_by`), ISNULL(`updated_date`), }
.q{ISNULL(`ppc_provider`), ISNULL(`account_name`), }
.q{ISNULL(`provider_account_id`), ISNULL(`campaign_name`), }
.q{ISNULL(`provider_campaign_id`), ISNULL(`adgroup_name`), }
.q{ISNULL(`provider_adgroup_id`), ISNULL(`provider_keyword_id`), }
.q{ISNULL(`provider_ad_id`), ISNULL(`foo`), ISNULL(`reason`), }
.q{ISNULL(`foo_base_foo_id`), ISNULL(`fooe_foo_id`)))) AS UNSIGNED)), 10, }
.q{16)) AS crc FROM `foo`.`bar` USE INDEX (`PRIMARY`) WHERE }
.q{(`id` >= 2166633); }),
'percona-toolkit',
'Fingerprints mk-table-checksum queries together',
);
is(
$qr->fingerprint("use `foo`"),
"use ?",
'Removes identifier from USE',
);
is(
$qr->fingerprint("select \n--bar\n foo"),
"select foo",
'Removes one-line comments in fingerprints',
);
is(
$qr->fingerprint("select foo--bar\nfoo"),
"select foo foo",
'Removes one-line comments in fingerprint without mushing things together',
);
is(
$qr->fingerprint("select foo -- bar\n"),
"select foo ",
'Removes one-line EOL comments in fingerprints',
);
# This one is too expensive!
#is(
# $qr->fingerprint(
# "select a,b ,c , d from tbl where a=5 or a = 5 or a=5 or a =5"),
# "select a, b, c, d from tbl where a=? or a=? or a=? or a=?",
# "Normalizes commas and equals",
#);
is(
$qr->fingerprint("select null, 5.001, 5001. from foo"),
"select ?, ?, ? from foo",
"Handles bug from perlmonks thread 728718",
);
is(
$qr->fingerprint("select 'hello', '\nhello\n', \"hello\", '\\'' from foo"),
"select ?, ?, ?, ? from foo",
"Handles quoted strings",
);
is(
$qr->fingerprint("select 'hello'\n"),
"select ?",
"Handles trailing newline",
);
# This is a known deficiency, fixes seem to be expensive though.
is(
$qr->fingerprint("select '\\\\' from foo"),
"select ? from foo",
"Does not handle all quoted strings",
);
is(
$qr->fingerprint("select foo"),
"select foo",
'Collapses whitespace',
);
is(
$qr->fingerprint('SELECT * from foo where a = 5'),
'select * from foo where a = ?',
'Lowercases, replaces integer',
);
is(
$qr->fingerprint('select 0e0, +6e-30, -6.00 from foo where a = 5.5 or b=0.5 or c=.5'),
'select ?, ?, ? from foo where a = ? or b=? or c=?',
'Floats',
);
is(
$qr->fingerprint("select 0x0, x'123', 0b1010, b'10101' from foo"),
'select ?, ?, ?, ? from foo',
'Hex/bit',
);
is(
$qr->fingerprint(" select * from\nfoo where a = 5"),
'select * from foo where a = ?',
'Collapses whitespace',
);
is(
$qr->fingerprint("select * from foo where a in (5) and b in (5, 8,9 ,9 , 10)"),
'select * from foo where a in(?+) and b in(?+)',
'IN lists',
);
is(
$qr->fingerprint("select foo_1 from foo_2_3"),
'select foo_? from foo_?_?',
'Numeric table names',
);
# 123f00 => ?oo because f "looks like it could be a number".
is(
$qr->fingerprint("select 123foo from 123foo", { prefixes => 1 }),
'select ?oo from ?oo',
'Numeric table name prefixes',
);
is(
$qr->fingerprint("select 123_foo from 123_foo", { prefixes => 1 }),
'select ?_foo from ?_foo',
'Numeric table name prefixes with underscores',
);
is(
$qr->fingerprint("insert into abtemp.coxed select foo.bar from foo"),
'insert into abtemp.coxed select foo.bar from foo',
'A string that needs no changes',
);
is(
$qr->fingerprint('insert into foo(a, b, c) values(2, 4, 5)'),
'insert into foo(a, b, c) values(?+)',
'VALUES lists',
);
is(
$qr->fingerprint('insert into foo(a, b, c) values(2, 4, 5) , (2,4,5)'),
'insert into foo(a, b, c) values(?+)',
'VALUES lists with multiple ()',
);
is(
$qr->fingerprint('insert into foo(a, b, c) value(2, 4, 5)'),
'insert into foo(a, b, c) value(?+)',
'VALUES lists with VALUE()',
);
is(
$qr->fingerprint('select * from foo limit 5'),
'select * from foo limit ?',
'limit alone',
);
is(
$qr->fingerprint('select * from foo limit 5, 10'),
'select * from foo limit ?',
'limit with comma-offset',
);
is(
$qr->fingerprint('select * from foo limit 5 offset 10'),
'select * from foo limit ?',
'limit with offset',
);
is(
$qr->fingerprint('select 1 union select 2 union select 4'),
'select ? /*repeat union*/',
'union fingerprints together',
);
is(
$qr->fingerprint('select 1 union all select 2 union all select 4'),
'select ? /*repeat union all*/',
'union all fingerprints together',
);
is(
$qr->fingerprint(
q{select * from (select 1 union all select 2 union all select 4) as x }
. q{join (select 2 union select 2 union select 3) as y}),
q{select * from (select ? /*repeat union all*/) as x }
. q{join (select ? /*repeat union*/) as y},
'union all fingerprints together',
);
# Issue 322: mk-query-digest segfault before report
is(
$qr->fingerprint( load_file('t/lib/samples/huge_replace_into_values.txt') ),
q{replace into `film_actor` values(?+)},
'huge replace into values() (issue 322)',
);
is(
$qr->fingerprint( load_file('t/lib/samples/huge_insert_ignore_into_values.txt') ),
q{insert ignore into `film_actor` values(?+)},
'huge insert ignore into values() (issue 322)',
);
is(
$qr->fingerprint( load_file('t/lib/samples/huge_explicit_cols_values.txt') ),
q{insert into foo (a,b,c,d,e,f,g,h) values(?+)},
'huge insert with explicit columns before values() (issue 322)',
);
# Those ^ aren't huge enough. This one is 1.2M large.
my $zcat = `uname` =~ m/Darwin/ ? 'gzcat' : 'zcat';
my $huge_insert = `$zcat $trunk/t/lib/samples/slowlogs/slow039.txt.gz | tail -n 1`;
is(
$qr->fingerprint($huge_insert),
q{insert into the_universe values(?+)},
'truly huge insert 1/2 (issue 687)'
);
$huge_insert = `$zcat $trunk/t/lib/samples/slowlogs/slow040.txt.gz | tail -n 2`;
is(
$qr->fingerprint($huge_insert),
q{insert into the_universe values(?+)},
'truly huge insert 2/2 (issue 687)'
);
# Issue 1030: Fingerprint can remove ORDER BY ASC
is(
$qr->fingerprint(
"select c from t where i=1 order by c asc",
),
"select c from t where i=? order by c",
"Remove ASC from ORDER BY"
);
is(
$qr->fingerprint(
"select * from t where i=1 order by a, b ASC, d DESC, e asc",
),
"select * from t where i=? order by a, b, d desc, e",
"Remove only ASC from ORDER BY"
);
is(
$qr->fingerprint(
"select * from t where i=1 order by
a, b ASC, d DESC,
e asc",
),
"select * from t where i=? order by a, b, d desc, e",
"Remove ASC from spacey ORDER BY"
);
is(
$qr->fingerprint("LOAD DATA INFILE '/tmp/foo.txt' INTO db.tbl"),
"load data infile ? into db.tbl",
"Fingerprint LOAD DATA INFILE"
);
# fingerprint MD5 checksums, 32 char hex strings. This is a
# special feature used by pt-fingerprint.
$qr = new QueryRewriter(
QueryParser => $qp,
match_md5_checksums => 1,
);
is(
$qr->fingerprint(
"SELECT * FROM db.fbc5e685a5d3d45aa1d0347fdb7c4d35_temp where id=1"
),
"select * from db.?_temp where id=?",
"Fingerprint db.MD5_tbl"
);
is(
$qr->fingerprint(
"SELECT * FROM db.temp_fbc5e685a5d3d45aa1d0347fdb7c4d35 where id=1"
),
"select * from db.temp_? where id=?",
"Fingerprint db.tbl_MD5"
);
$qr = new QueryRewriter(
QueryParser => $qp,
match_md5_checksums => 1,
match_embedded_numbers => 1,
);
is(
$qr->fingerprint(
"SELECT * FROM db.fbc5e685a5d3d45aa1d0347fdb7c4d35_temp where id=1"
),
"select * from db.?_temp where id=?",
"Fingerprint db.MD5_tbl (with match_embedded_numbers)"
);
is(
$qr->fingerprint(
"SELECT * FROM db.temp_fbc5e685a5d3d45aa1d0347fdb7c4d35 where id=1"
),
"select * from db.temp_? where id=?",
"Fingerprint db.tbl_MD5 (with match_embedded_numbers)"
);
$qr = new QueryRewriter(
QueryParser => $qp,
match_embedded_numbers => 1,
);
is(
$qr->fingerprint(
"SELECT * FROM prices.rt_5min where id=1"
),
"select * from prices.rt_5min where id=?",
"Fingerprint db.tbl<number>name (preserve number)"
);
is(
$qr->fingerprint(
"/* -- S++ SU ABORTABLE -- spd_user: rspadim */SELECT SQL_SMALL_RESULT SQL_CACHE DISTINCT centro_atividade FROM est_dia WHERE unidade_id=1001 AND item_id=67 AND item_id_red=573"
),
"select sql_small_result sql_cache distinct centro_atividade from est_dia where unidade_id=? and item_id=? and item_id_red=?",
"Fingerprint /* -- comment */ SELECT (bug 1174956)"
);
# issue 965553
is(
$qr->fingerprint('SELECT * FROM tbl WHERE id=1 AND flag=true AND trueflag=FALSE'),
'select * from tbl where id=? and flag=? and trueflag=?',
'boolean values abstracted correctly',
);
# #############################################################################
# convert_to_select()
# #############################################################################
is($qr->convert_to_select(), undef, 'No query');
is(
$qr->convert_to_select(
'select * from tbl where id = 1'
),
'select * from tbl where id = 1',
'Does not convert select to select',
);
is(
$qr->convert_to_select(q{INSERT INTO foo.bar (col1, col2, col3)
VALUES ('unbalanced(', 'val2', 3)}),
q{select * from foo.bar where col1='unbalanced(' and }
. q{col2= 'val2' and col3= 3},
'unbalanced paren inside a string in VALUES',
);
# convert REPLACE #############################################################
is(
$qr->convert_to_select(
'replace into foo select * from bar',
),
'select * from bar',
'convert REPLACE SELECT',
);
is(
$qr->convert_to_select(
'replace into foo select`faz` from bar',
),
'select`faz` from bar',
'convert REPLACE SELECT`col`',
);
is(
$qr->convert_to_select(
'replace into foo(a, b, c) values(1, 3, 5) on duplicate key update foo=bar',
),
'select * from foo where a=1 and b= 3 and c= 5',
'convert REPLACE (cols) VALUES ON DUPE KEY',
);
is(
$qr->convert_to_select(
'replace into foo(a, b, c) values(now(), "3", 5)',
),
'select * from foo where a=now() and b= "3" and c= 5',
'convert REPLACE (cols) VALUES (now())',
);
is(
$qr->convert_to_select(
'replace into foo(a, b, c) values(current_date - interval 1 day, "3", 5)',
),
'select * from foo where a=current_date - interval 1 day and b= "3" and c= 5',
'convert REPLACE (cols) VALUES (complex expression)',
);
is(
$qr->convert_to_select(q{
REPLACE DELAYED INTO
`db1`.`tbl2`(`col1`,col2)
VALUES ('617653','2007-09-11')}),
qq{select * from \n`db1`.`tbl2` where `col1`='617653' and col2='2007-09-11'},
'convert REPLACE DELAYED (cols) VALUES',
);
is(
$qr->convert_to_select(
'replace into tbl set col1="a val", col2=123, col3=null',
),
'select * from tbl where col1="a val" and col2=123 and col3=null ',
'convert REPLACE SET'
);
# convert INSERT ##############################################################
is(
$qr->convert_to_select(
'insert into foo(a, b, c) values(1, 3, 5)',
),
'select * from foo where a=1 and b= 3 and c= 5',
'convert INSERT (cols) VALUES',
);
is(
$qr->convert_to_select(
'insert into foo(a, b, c) value(1, 3, 5)',
),
'select * from foo where a=1 and b= 3 and c= 5',
'convert INSERT (cols) VALUE',
);
# Issue 599: mk-slave-prefetch doesn't parse INSERT IGNORE
is(
$qr->convert_to_select(
'insert ignore into foo(a, b, c) values(1, 3, 5)',
),
'select * from foo where a=1 and b= 3 and c= 5',
'convert INSERT IGNORE (cols) VALUES',
);
is(
$qr->convert_to_select(
'INSERT IGNORE INTO Foo (clm1, clm2) VALUE (1,2)',
),
'select * from Foo where clm1=1 and clm2=2',
'convert INSERT IGNORE (cols) VALUE',
);
is(
$qr->convert_to_select(
'insert into foo select * from bar join baz using (bat)',
),
'select * from bar join baz using (bat)',
'convert INSERT SELECT',
);
# Issue 600: mk-slave-prefetch doesn't parse INSERT INTO Table SET c1 = v1,
# c2 = v2 ...
is(
$qr->convert_to_select(
"INSERT INTO Table SET c1 = 'v1', c2 = 'v2', c3 = 'v3'",
),
"select * from Table where c1 = 'v1' and c2 = 'v2' and c3 = 'v3' ",
'convert INSERT SET char cols',
);
is(
$qr->convert_to_select(
"INSERT INTO db.tbl SET c1=NULL,c2=42,c3='some value with spaces'",
),
"select * from db.tbl where c1=NULL and c2=42 and c3='some value with spaces' ",
'convert INSERT SET NULL col, int col, char col with space',
);
is(
$qr->convert_to_select(
'insert into foo (col1) values (1) on duplicate key update',
),
'select * from foo where col1=1',
'convert INSERT (cols) VALUES ON DUPE KEY UPDATE'
);
is(
$qr->convert_to_select(
'insert into foo (col1) value (1) on duplicate key update',
),
'select * from foo where col1=1',
'convert INSERT (cols) VALUE ON DUPE KEY UPDATE'
);
is(
$qr->convert_to_select(
"insert into tbl set col='foo', col2='some val' on duplicate key update",
),
"select * from tbl where col='foo' and col2='some val' ",
'convert INSERT SET ON DUPE KEY UPDATE',
);
is(
$qr->convert_to_select(
'insert into foo select * from bar where baz=bat on duplicate key update',
),
'select * from bar where baz=bat',
'convert INSERT SELECT ON DUPE KEY UPDATE',
);
# convert UPDATE ##############################################################
is(
$qr->convert_to_select(
'update foo set bar=baz where bat=fiz',
),
'select bar=baz from foo where bat=fiz',
'update set',
);
is(
$qr->convert_to_select(
'update foo inner join bar using(baz) set big=little',
),
'select big=little from foo inner join bar using(baz) ',
'delete inner join',
);
is(
$qr->convert_to_select(
'update foo set bar=baz limit 50',
),
'select bar=baz from foo limit 50 ',
'update with limit',
);
is(
$qr->convert_to_select(
q{UPDATE foo.bar
SET whereproblem= '3364', apple = 'fish'
WHERE gizmo='5091'}
),
q{select whereproblem= '3364', apple = 'fish' from foo.bar where gizmo='5091'},
'unknown issue',
);
# Insanity...
is(
$qr->convert_to_select('
update db2.tbl1 as p
inner join (
select p2.col1, p2.col2
from db2.tbl1 as p2
inner join db2.tbl3 as ba
on p2.col1 = ba.tbl3
where col4 = 0
order by priority desc, col1, col2
limit 10
) as chosen on chosen.col1 = p.col1
and chosen.col2 = p.col2
set p.col4 = 149945'),
'select p.col4 = 149945 from db2.tbl1 as p
inner join (
select p2.col1, p2.col2
from db2.tbl1 as p2
inner join db2.tbl3 as ba
on p2.col1 = ba.tbl3
where col4 = 0
order by priority desc, col1, col2
limit 10
) as chosen on chosen.col1 = p.col1
and chosen.col2 = p.col2 ',
'SELECT in the FROM clause',
);
is(
$qr->convert_to_select("UPDATE tbl SET col='wherex'WHERE crazy=1"),
"select col='wherex' from tbl where crazy=1",
"update with SET col='wherex'WHERE"
);
is($qr->convert_to_select(
q{UPDATE GARDEN_CLUPL PL, GARDENJOB GC, APLTRACT_GARDENPLANT ABU SET }
. q{GC.MATCHING_POT = 5, GC.LAST_GARDENPOT = 5, GC.LAST_NAME=}
. q{'Rotary', GC.LAST_BUCKET='Pail', GC.LAST_UPDATE='2008-11-27 04:00:59'WHERE}
. q{ PL.APLTRACT_GARDENPLANT_ID = GC.APLTRACT_GARDENPLANT_ID AND PL.}
. q{APLTRACT_GARDENPLANT_ID = ABU.ID AND GC.MATCHING_POT = 0 AND GC.PERFORM_DIG=1}
. q{ AND ABU.DIG = 6 AND ( ((SOIL-COST) > -80.0}
. q{ AND BUGS < 60.0 AND (SOIL-COST) < 200.0) AND POTS < 10.0 )}),
"select GC.MATCHING_POT = 5, GC.LAST_GARDENPOT = 5, GC.LAST_NAME='Rotary', GC.LAST_BUCKET='Pail', GC.LAST_UPDATE='2008-11-27 04:00:59' from GARDEN_CLUPL PL, GARDENJOB GC, APLTRACT_GARDENPLANT ABU where PL.APLTRACT_GARDENPLANT_ID = GC.APLTRACT_GARDENPLANT_ID AND PL.APLTRACT_GARDENPLANT_ID = ABU.ID AND GC.MATCHING_POT = 0 AND GC.PERFORM_DIG=1 AND ABU.DIG = 6 AND ( ((SOIL-COST) > -80.0 AND BUGS < 60.0 AND (SOIL-COST) < 200.0) AND POTS < 10.0 )",
'update with no space between quoted string and where (issue 168)'
);
is(
$qr->convert_to_select("UPDATE LOW_PRIORITY db.tbl SET field='new' WHERE id=1"),
"select field='new' from db.tbl where id=1",
"update with LOW_PRIORITY"
);
is(
$qr->convert_to_select("UPDATE ignore db.tbl SET field='new' WHERE id=1"),
"select field='new' from db.tbl where id=1",
"update with IGNORE"
);
# convert DELETE ##############################################################
is(
$qr->convert_to_select(
'delete from foo where bar = baz',
),
'select * from foo where bar = baz',
'delete',
);
is(
$qr->convert_to_select(q{delete foo.bar b from foo.bar b left join baz.bat c on a=b where nine>eight}),
'select 1 from foo.bar b left join baz.bat c on a=b where nine>eight',
'Do not select * from a join',
);
is(
$qr->convert_to_select("DELETE LOW_PRIORITY FROM tbl WHERE id=1"),
"select * from tbl WHERE id=1",
"delete with LOW_PRIORITY"
);
is(
$qr->convert_to_select("delete ignore from tbl WHERE id=1"),
"select * from tbl WHERE id=1",
"delete with IGNORE"
);
is(
$qr->convert_to_select("delete from file where id='ima-long-uuid-string'"),
"select * from file where id='ima-long-uuid-string'",
"Peter's DELTE"
);
# do not convert subqueries ###################################################
is(
$qr->convert_to_select("UPDATE mybbl_MBMessage SET groupId = (select groupId from Group_ where name = 'Guest')"),
undef,
'Do not convert subquery'
);
# #############################################################################
# wrap_in_derived()
# #############################################################################
is($qr->wrap_in_derived(), undef, 'Cannot wrap undef');
is(
$qr->wrap_in_derived(
'select * from foo',
),
'select 1 from (select * from foo) as x limit 1',
'wrap in derived table',
);
is(
$qr->wrap_in_derived('set timestamp=134'),
'set timestamp=134',
'Do not wrap non-SELECT queries',
);
# #############################################################################
# convert_select_list()
# #############################################################################
is(
$qr->convert_select_list('select * from tbl'),
'select 1 from tbl',
'Star to one',
);
is(
$qr->convert_select_list('select a, b, c from tbl'),
'select isnull(coalesce( a, b, c )) from tbl',
'column list to isnull/coalesce'
);
# #############################################################################
# shorten()
# #############################################################################
is(
$qr->shorten("insert into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i)"),
"insert into t(a,b,c) values(a,b,c) /*... omitted ...*/",
"shorten simple insert",
);
is(
$qr->shorten("insert low_priority into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i)"),
"insert low_priority into t(a,b,c) values(a,b,c) /*... omitted ...*/",
"shorten low_priority simple insert",
);
is(
$qr->shorten("insert delayed into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i)"),
"insert delayed into t(a,b,c) values(a,b,c) /*... omitted ...*/",
"shorten delayed simple insert",
);
is(
$qr->shorten("insert high_priority into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i)"),
"insert high_priority into t(a,b,c) values(a,b,c) /*... omitted ...*/",
"shorten high_priority simple insert",
);
is(
$qr->shorten("insert ignore into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i)"),
"insert ignore into t(a,b,c) values(a,b,c) /*... omitted ...*/",
"shorten ignore simple insert",
);
is(
$qr->shorten("insert high_priority ignore into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i)"),
"insert high_priority ignore into t(a,b,c) values(a,b,c) /*... omitted ...*/",
"shorten high_priority ignore simple insert",
);
is(
$qr->shorten("replace low_priority into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i)"),
"replace low_priority into t(a,b,c) values(a,b,c) /*... omitted ...*/",
"shorten replace low_priority",
);
is(
$qr->shorten("replace delayed into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i)"),
"replace delayed into t(a,b,c) values(a,b,c) /*... omitted ...*/",
"shorten replace delayed",
);
is(
$qr->shorten("insert into t(a,b,c) values(a,b,c),(d,e,f),(g,h,i) on duplicate key update a = b"),
"insert into t(a,b,c) values(a,b,c) /*... omitted ...*/on duplicate key update a = b",
"shorten insert ... odku",
);
is(
$qr->shorten(
"select * from a where b in(" . join(',', 1..60) . ") and "
. "a in(" . join(',', 1..5000) . ")", 1),
"select * from a where b in(" . join(',', 1..20) . "/*... omitted 40 items ...*/)"
. " and a in(" . join(',', 1..20) . "/*... omitted 4980 items ...*/)",
"shorten two IN() lists of numbers",
);
is(
$qr->shorten("select * from a", 1),
"select * from a",
"Does not shorten strings it does not match",
);
is(
$qr->shorten("select * from a where b in(". join(',', 1..100) . ")", 1024),
"select * from a where b in(". join(',', 1..100) . ")",
"shorten IN() list numbers but not those that are already short enough",
);
is(
$qr->shorten("select * from a where b in(" . join(',', 1..100) . "'a,b')", 1),
"select * from a where b in(" . join(',', 1..20) . "/*... omitted 81 items ...*/)",
"Test case to document that commas are expected to mess up omitted count",
);
is(
$qr->shorten("select * from a where b in(1, 'a)b', " . join(',', 1..100) . ")", 1),
"select * from a where b in(1, 'a)b', " . join(',', 1..100) . ")",
"Test case to document that parens are expected to prevent shortening",
);
# #############################################################################
# distill()
# All tests below here are distill() tests. There's a lot of them.
# #############################################################################
is(
$qr->distill("SELECT /*!40001 SQL_NO_CACHE */ * FROM `film`"),
"SELECT film",
'Distills mysqldump SELECTs to selects',
);
is(
$qr->distill("CALL foo(1, 2, 3)"),
"CALL foo",
'Distills stored procedure calls specially',
);
is(
$qr->distill(
q{REPLACE /*foo.bar:3/3*/ INTO checksum.checksum (db, tbl, }
.q{chunk, boundaries, this_cnt, this_crc) SELECT 'foo', 'bar', }
.q{2 AS chunk_num, '`id` >= 2166633', COUNT(*) AS cnt, }
.q{LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `id`, `created_by`, }
.q{`created_date`, `updated_by`, `updated_date`, `ppc_provider`, }
.q{`account_name`, `provider_account_id`, `campaign_name`, }
.q{`provider_campaign_id`, `adgroup_name`, `provider_adgroup_id`, }
.q{`provider_keyword_id`, `provider_ad_id`, `foo`, `reason`, }
.q{`foo_bar_bazz_id`, `foo_bar_baz`, CONCAT(ISNULL(`created_by`), }
.q{ISNULL(`created_date`), ISNULL(`updated_by`), ISNULL(`updated_date`), }
.q{ISNULL(`ppc_provider`), ISNULL(`account_name`), }
.q{ISNULL(`provider_account_id`), ISNULL(`campaign_name`), }
.q{ISNULL(`provider_campaign_id`), ISNULL(`adgroup_name`), }
.q{ISNULL(`provider_adgroup_id`), ISNULL(`provider_keyword_id`), }
.q{ISNULL(`provider_ad_id`), ISNULL(`foo`), ISNULL(`reason`), }
.q{ISNULL(`foo_base_foo_id`), ISNULL(`fooe_foo_id`)))) AS UNSIGNED)), 10, }
.q{16)) AS crc FROM `foo`.`bar` USE INDEX (`PRIMARY`) WHERE }
.q{(`id` >= 2166633); }),
'REPLACE SELECT checksum.checksum foo.bar',
'Distills mk-table-checksum query',
);
is(
$qr->distill("use `foo`"),
"USE",
'distills USE',
);
is(
$qr->distill(q{delete foo.bar b from foo.bar b left join baz.bat c on a=b where nine>eight}),
'DELETE foo.bar baz.bat',
'distills and then collapses same tables',
);
is(
$qr->distill("select \n--bar\n foo"),
"SELECT",
'distills queries from DUAL',
);
is(
$qr->distill("select null, 5.001, 5001. from foo"),
"SELECT foo",
"distills simple select",
);
is(
$qr->distill("select 'hello', '\nhello\n', \"hello\", '\\'' from foo"),
"SELECT foo",
"distills with quoted strings",
);
is(
$qr->distill("select foo_1 from foo_2_3"),
'SELECT foo_?_?',
'distills numeric table names',
);
is(
$qr->distill("insert into abtemp.coxed select foo.bar from foo"),
'INSERT SELECT abtemp.coxed foo',
'distills insert/select',
);
is(
$qr->distill('insert into foo(a, b, c) values(2, 4, 5)'),
'INSERT foo',
'distills value lists',
);
is(
$qr->distill('select 1 union select 2 union select 4'),
'SELECT UNION',
'distill unions together',
);
is(
$qr->distill(
'delete from foo where bar = baz',
),
'DELETE foo',
'distills delete',
);
is(
$qr->distill('set timestamp=134'),
'SET',
'distills set',
);
is(
$qr->distill(
'replace into foo(a, b, c) values(1, 3, 5) on duplicate key update foo=bar',
),
'REPLACE UPDATE foo',
'distills ODKU',
);
is($qr->distill(
q{UPDATE GARDEN_CLUPL PL, GARDENJOB GC, APLTRACT_GARDENPLANT ABU SET }
. q{GC.MATCHING_POT = 5, GC.LAST_GARDENPOT = 5, GC.LAST_NAME=}
. q{'Rotary', GC.LAST_BUCKET='Pail', GC.LAST_UPDATE='2008-11-27 04:00:59'WHERE}
. q{ PL.APLTRACT_GARDENPLANT_ID = GC.APLTRACT_GARDENPLANT_ID AND PL.}
. q{APLTRACT_GARDENPLANT_ID = ABU.ID AND GC.MATCHING_POT = 0 AND GC.PERFORM_DIG=1}
. q{ AND ABU.DIG = 6 AND ( ((SOIL-COST) > -80.0}
. q{ AND BUGS < 60.0 AND (SOIL-COST) < 200.0) AND POTS < 10.0 )}),
'UPDATE GARDEN_CLUPL GARDENJOB APLTRACT_GARDENPLANT',
'distills where there is alias and comma-join',
);
is(
$qr->distill(q{SELECT STRAIGHT_JOIN distinct foo, bar FROM A, B, C}),
'SELECT A B C',
'distill with STRAIGHT_JOIN',
);
is (
$qr->distill(q{
REPLACE DELAYED INTO
`db1`.`tbl2`(`col1`,col2)
VALUES ('617653','2007-09-11')}),
'REPLACE db?.tbl?',
'distills replace-delayed',
);
is(
$qr->distill(
'update foo inner join bar using(baz) set big=little',
),
'UPDATE foo bar',
'distills update-multi',
);
is(
$qr->distill('
update db2.tbl1 as p
inner join (
select p2.col1, p2.col2
from db2.tbl1 as p2
inner join db2.tbl3 as ba
on p2.col1 = ba.tbl3
where col4 = 0
order by priority desc, col1, col2
limit 10
) as chosen on chosen.col1 = p.col1
and chosen.col2 = p.col2
set p.col4 = 149945'),
'UPDATE SELECT db?.tbl?',
'distills complex subquery',
);
is(
$qr->distill(
'replace into checksum.checksum select `last_update`, `foo` from foo.foo'),
'REPLACE SELECT checksum.checksum foo.foo',
'distill with reserved words');
is($qr->distill('SHOW STATUS'), 'SHOW STATUS', 'distill SHOW STATUS');
is($qr->distill('commit'), 'COMMIT', 'distill COMMIT');
is($qr->distill('FLUSH TABLES WITH READ LOCK'), 'FLUSH', 'distill FLUSH');
is($qr->distill('BEGIN'), 'BEGIN', 'distill BEGIN');
is($qr->distill('start'), 'START', 'distill START');
is($qr->distill('ROLLBACK'), 'ROLLBACK', 'distill ROLLBACK');
is(
$qr->distill(
'insert into foo select * from bar join baz using (bat)',
),
'INSERT SELECT foo bar baz',
'distills insert select',
);
is(
$qr->distill('create database foo'),
'CREATE DATABASE foo',
'distills create database'
);
is(
$qr->distill('create table foo'),
'CREATE TABLE foo',
'distills create table'
);
is(
$qr->distill('alter database foo'),
'ALTER DATABASE foo',
'distills alter database'
);
is(
$qr->distill('alter table foo'),
'ALTER TABLE foo',
'distills alter table'
);
is(
$qr->distill('drop database foo'),
'DROP DATABASE foo',
'distills drop database'
);
is(
$qr->distill('drop table foo'),
'DROP TABLE foo',
'distills drop table'
);
is(
$qr->distill('rename database foo'),
'RENAME DATABASE foo',
'distills rename database'
);
is(
$qr->distill('rename table foo'),
'RENAME TABLE foo',
'distills rename table'
);
is(
$qr->distill('truncate table foo'),
'TRUNCATE TABLE foo',
'distills truncate table'
);
# Test generic distillation for memcached, http, etc.
my $trf = sub {
my ( $query ) = @_;
$query =~ s/(\S+ \S+?)(?:[?;].+)/$1/;
return $query;
};
is(
$qr->distill('get percona.com/', generic => 1, trf => $trf),
'GET percona.com/',
'generic distill HTTP get'
);
is(
$qr->distill('get percona.com/page.html?some=thing', generic => 1, trf => $trf),
'GET percona.com/page.html',
'generic distill HTTP get with args'
);
is(
$qr->distill('put percona.com/contacts.html', generic => 1, trf => $trf),
'PUT percona.com/contacts.html',
'generic distill HTTP put'
);
is(
$qr->distill(
'update foo set bar=baz where bat=fiz',
),
'UPDATE foo',
'distills update',
);
# Issue 563: Lock tables is not distilled
is(
$qr->distill('LOCK TABLES foo WRITE'),
'LOCK foo',
'distills lock tables'
);
is(
$qr->distill('LOCK TABLES foo READ, bar WRITE'),
'LOCK foo bar',
'distills lock tables (2 tables)'
);
is(
$qr->distill('UNLOCK TABLES'),
'UNLOCK',
'distills unlock tables'
);
# Issue 712: Queries not handled by "distill"
is(
$qr->distill('XA START 0x123'),
'XA_START',
'distills xa start'
);
is(
$qr->distill('XA PREPARE 0x123'),
'XA_PREPARE',
'distills xa prepare'
);
is(
$qr->distill('XA COMMIT 0x123'),
'XA_COMMIT',
'distills xa commit'
);
is(
$qr->distill('XA END 0x123'),
'XA_END',
'distills xa end'
);
is(
$qr->distill("/* mysql-connector-java-5.1-nightly-20090730 ( Revision: \${svn.Revision} ) */SHOW VARIABLES WHERE Variable_name ='language' OR Variable_name =
'net_write_timeout' OR Variable_name = 'interactive_timeout' OR
Variable_name = 'wait_timeout' OR Variable_name = 'character_set_client' OR
Variable_name = 'character_set_connection' OR Variable_name =
'character_set' OR Variable_name = 'character_set_server' OR Variable_name
= 'tx_isolation' OR Variable_name = 'transaction_isolation' OR
Variable_name = 'character_set_results' OR Variable_name = 'timezone' OR
Variable_name = 'time_zone' OR Variable_name = 'system_time_zone' OR
Variable_name = 'lower_case_table_names' OR Variable_name =
'max_allowed_packet' OR Variable_name = 'net_buffer_length' OR
Variable_name = 'sql_mode' OR Variable_name = 'query_cache_type' OR
Variable_name = 'query_cache_size' OR Variable_name = 'init_connect'"),
'SHOW VARIABLES',
'distills /* comment */SHOW VARIABLES'
);
# This is a list of all the types of syntax for SHOW on
# http://dev.mysql.com/doc/refman/5.0/en/show.html
my %status_tests = (
'SHOW BINARY LOGS' => 'SHOW BINARY LOGS',
'SHOW BINLOG EVENTS in "log_name"' => 'SHOW BINLOG EVENTS',
'SHOW CHARACTER SET LIKE "pattern"' => 'SHOW CHARACTER SET',
'SHOW COLLATION WHERE "something"' => 'SHOW COLLATION',
'SHOW COLUMNS FROM tbl' => 'SHOW COLUMNS',
'SHOW FULL COLUMNS FROM tbl' => 'SHOW COLUMNS',
'SHOW COLUMNS FROM tbl in db' => 'SHOW COLUMNS',
'SHOW COLUMNS FROM tbl IN db LIKE "pattern"' => 'SHOW COLUMNS',
'SHOW CREATE DATABASE db_name' => 'SHOW CREATE DATABASE',
'SHOW CREATE SCHEMA db_name' => 'SHOW CREATE DATABASE',
'SHOW CREATE FUNCTION func' => 'SHOW CREATE FUNCTION',
'SHOW CREATE PROCEDURE proc' => 'SHOW CREATE PROCEDURE',
'SHOW CREATE TABLE tbl_name' => 'SHOW CREATE TABLE',
'SHOW CREATE VIEW vw_name' => 'SHOW CREATE VIEW',
'SHOW DATABASES' => 'SHOW DATABASES',
'SHOW SCHEMAS' => 'SHOW DATABASES',
'SHOW DATABASES LIKE "pattern"' => 'SHOW DATABASES',
'SHOW DATABASES WHERE foo=bar' => 'SHOW DATABASES',
'SHOW ENGINE ndb status' => 'SHOW NDB STATUS',
'SHOW ENGINE innodb status' => 'SHOW INNODB STATUS',
'SHOW ENGINES' => 'SHOW ENGINES',
'SHOW STORAGE ENGINES' => 'SHOW ENGINES',
'SHOW ERRORS' => 'SHOW ERRORS',
'SHOW ERRORS limit 5' => 'SHOW ERRORS',
'SHOW COUNT(*) ERRORS' => 'SHOW ERRORS',
'SHOW FUNCTION CODE func' => 'SHOW FUNCTION CODE',
'SHOW FUNCTION STATUS' => 'SHOW FUNCTION STATUS',
'SHOW FUNCTION STATUS LIKE "pattern"' => 'SHOW FUNCTION STATUS',
'SHOW FUNCTION STATUS WHERE foo=bar' => 'SHOW FUNCTION STATUS',
'SHOW GRANTS' => 'SHOW GRANTS',
'SHOW GRANTS FOR user@localhost' => 'SHOW GRANTS',
'SHOW INDEX' => 'SHOW INDEX',
'SHOW INDEXES' => 'SHOW INDEX',
'SHOW KEYS' => 'SHOW INDEX',
'SHOW INDEX FROM tbl' => 'SHOW INDEX',
'SHOW INDEX FROM tbl IN db' => 'SHOW INDEX',
'SHOW INDEX IN tbl FROM db' => 'SHOW INDEX',
'SHOW INNODB STATUS' => 'SHOW INNODB STATUS',
'SHOW LOGS' => 'SHOW LOGS',
'SHOW MASTER STATUS' => 'SHOW MASTER STATUS',
'SHOW MUTEX STATUS' => 'SHOW MUTEX STATUS',
'SHOW OPEN TABLES' => 'SHOW OPEN TABLES',
'SHOW OPEN TABLES FROM db' => 'SHOW OPEN TABLES',
'SHOW OPEN TABLES IN db' => 'SHOW OPEN TABLES',
'SHOW OPEN TABLES IN db LIKE "pattern"' => 'SHOW OPEN TABLES',
'SHOW OPEN TABLES IN db WHERE foo=bar' => 'SHOW OPEN TABLES',
'SHOW OPEN TABLES WHERE foo=bar' => 'SHOW OPEN TABLES',
'SHOW PRIVILEGES' => 'SHOW PRIVILEGES',
'SHOW PROCEDURE CODE proc' => 'SHOW PROCEDURE CODE',
'SHOW PROCEDURE STATUS' => 'SHOW PROCEDURE STATUS',
'SHOW PROCEDURE STATUS LIKE "pattern"' => 'SHOW PROCEDURE STATUS',
'SHOW PROCEDURE STATUS WHERE foo=bar' => 'SHOW PROCEDURE STATUS',
'SHOW PROCESSLIST' => 'SHOW PROCESSLIST',
'SHOW FULL PROCESSLIST' => 'SHOW PROCESSLIST',
'SHOW PROFILE' => 'SHOW PROFILE',
'SHOW PROFILES' => 'SHOW PROFILES',
'SHOW PROFILES CPU FOR QUERY 1' => 'SHOW PROFILES CPU',
'SHOW SLAVE HOSTS' => 'SHOW SLAVE HOSTS',
'SHOW SLAVE STATUS' => 'SHOW SLAVE STATUS',
'SHOW STATUS' => 'SHOW STATUS',
'SHOW GLOBAL STATUS' => 'SHOW GLOBAL STATUS',
'SHOW SESSION STATUS' => 'SHOW STATUS',
'SHOW STATUS LIKE "pattern"' => 'SHOW STATUS',
'SHOW STATUS WHERE foo=bar' => 'SHOW STATUS',
'SHOW TABLE STATUS' => 'SHOW TABLE STATUS',
'SHOW TABLE STATUS FROM db_name' => 'SHOW TABLE STATUS',
'SHOW TABLE STATUS IN db_name' => 'SHOW TABLE STATUS',
'SHOW TABLE STATUS LIKE "pattern"' => 'SHOW TABLE STATUS',
'SHOW TABLE STATUS WHERE foo=bar' => 'SHOW TABLE STATUS',
'SHOW TABLES' => 'SHOW TABLES',
'SHOW FULL TABLES' => 'SHOW TABLES',
'SHOW TABLES FROM db' => 'SHOW TABLES',
'SHOW TABLES IN db' => 'SHOW TABLES',
'SHOW TABLES LIKE "pattern"' => 'SHOW TABLES',
'SHOW TABLES FROM db LIKE "pattern"' => 'SHOW TABLES',
'SHOW TABLES WHERE foo=bar' => 'SHOW TABLES',
'SHOW TRIGGERS' => 'SHOW TRIGGERS',
'SHOW TRIGGERS IN db' => 'SHOW TRIGGERS',
'SHOW TRIGGERS FROM db' => 'SHOW TRIGGERS',
'SHOW TRIGGERS LIKE "pattern"' => 'SHOW TRIGGERS',
'SHOW TRIGGERS WHERE foo=bar' => 'SHOW TRIGGERS',
'SHOW VARIABLES' => 'SHOW VARIABLES',
'SHOW GLOBAL VARIABLES' => 'SHOW GLOBAL VARIABLES',
'SHOW SESSION VARIABLES' => 'SHOW VARIABLES',
'SHOW VARIABLES LIKE "pattern"' => 'SHOW VARIABLES',
'SHOW VARIABLES WHERE foo=bar' => 'SHOW VARIABLES',
'SHOW WARNINGS' => 'SHOW WARNINGS',
'SHOW WARNINGS LIMIT 5' => 'SHOW WARNINGS',
'SHOW COUNT(*) WARNINGS' => 'SHOW WARNINGS',
'SHOW COUNT ( *) WARNINGS' => 'SHOW WARNINGS',
);
foreach my $key ( keys %status_tests ) {
is($qr->distill($key), $status_tests{$key}, "distills $key");
}
is(
$qr->distill('SHOW SLAVE STATUS'),
'SHOW SLAVE STATUS',
'distills SHOW SLAVE STATUS'
);
is(
$qr->distill('SHOW INNODB STATUS'),
'SHOW INNODB STATUS',
'distills SHOW INNODB STATUS'
);
is(
$qr->distill('SHOW CREATE TABLE'),
'SHOW CREATE TABLE',
'distills SHOW CREATE TABLE'
);
my @show = qw(COLUMNS GRANTS INDEX STATUS TABLES TRIGGERS WARNINGS);
foreach my $show ( @show ) {
is(
$qr->distill("SHOW $show"),
"SHOW $show",
"distills SHOW $show"
);
}
# Issue 735: mk-query-digest doesn't distill query correctly
is(
$qr->distill('SHOW /*!50002 GLOBAL */ STATUS'),
'SHOW GLOBAL STATUS',
"distills SHOW /*!50002 GLOBAL */ STATUS"
);
is(
$qr->distill('SHOW /*!50002 ENGINE */ INNODB STATUS'),
'SHOW INNODB STATUS',
"distills SHOW INNODB STATUS"
);
is(
$qr->distill('SHOW MASTER LOGS'),
'SHOW MASTER LOGS',
"distills SHOW MASTER LOGS"
);
is(
$qr->distill('SHOW GLOBAL STATUS'),
'SHOW GLOBAL STATUS',
"distills SHOW GLOBAL STATUS"
);
is(
$qr->distill('SHOW GLOBAL VARIABLES'),
'SHOW GLOBAL VARIABLES',
"distills SHOW GLOBAL VARIABLES"
);
is(
$qr->distill('administrator command: Statistics'),
'ADMIN STATISTICS',
"distills ADMIN STATISTICS"
);
# Issue 781: mk-query-digest doesn't distill or extract tables properly
is(
$qr->distill("SELECT `id` FROM (`field`) WHERE `id` = '10000016228434112371782015185031'"),
'SELECT field',
'distills SELECT clm from (`tbl`)'
);
is(
$qr->distill("INSERT INTO (`jedi_forces`) (name, side, email) values ('Anakin Skywalker', 'jedi', 'anakin_skywalker_at_jedi.sw')"),
'INSERT jedi_forces',
'distills INSERT INTO (`tbl`)'
);
is(
$qr->distill("UPDATE (`jedi_forces`) set side = 'dark' and name = 'Lord Vader' where name = 'Anakin Skywalker'"),
'UPDATE jedi_forces',
'distills UPDATE (`tbl`)'
);
is(
$qr->distill("select c from (tbl1 JOIN tbl2 on (id)) where x=y"),
'SELECT tbl?',
'distills SELECT (t1 JOIN t2)'
);
is(
$qr->distill("insert into (t1) value('a')"),
'INSERT t?',
'distills INSERT (tbl)'
);
# Something that will (should) never distill.
is(
$qr->distill("-- how /*did*/ `THIS` #happen?"),
'',
'distills nonsense'
);
is(
$qr->distill("peek tbl poke db"),
'',
'distills non-SQL'
);
# Issue 1176: mk-query-digest incorrectly distills queries with certain keywords
# I want to see first how this is handled. It's correct because the query
# really does read from tables a and c; table b is just an alias.
is(
$qr->distill("select c from (select * from a) as b where exists (select * from c where id is null)"),
"SELECT a c",
"distills SELECT with subquery in FROM and WHERE"
);
is(
$qr->distill("select c from t where col='delete'"),
'SELECT t',
'distills SELECT with keyword as value (issue 1176)'
);
is(
$qr->distill('SELECT c, replace(foo, bar) FROM t WHERE col <> "insert"'),
'SELECT t',
'distills SELECT with REPLACE function (issue 1176)'
);
# LOAD DATA
# https://bugs.launchpad.net/percona-toolkit/+bug/821692
# INSERT and REPLACE without INTO
# https://bugs.launchpad.net/percona-toolkit/+bug/984053
is(
$qr->distill("LOAD DATA LOW_PRIORITY LOCAL INFILE 'file' INTO TABLE tbl"),
"LOAD DATA tbl",
"distill LOAD DATA (bug 821692)"
);
is(
$qr->distill("LOAD DATA LOW_PRIORITY LOCAL INFILE 'file' INTO TABLE `tbl`"),
"LOAD DATA tbl",
"distill LOAD DATA (bug 821692)"
);
is(
$qr->distill("insert ignore_bar (id) values (4029731)"),
"INSERT ignore_bar",
"distill INSERT without INTO (bug 984053)"
);
is(
$qr->distill("replace ignore_bar (id) values (4029731)"),
"REPLACE ignore_bar",
"distill REPLACE without INTO (bug 984053)"
);
# IF EXISTS
# https://bugs.launchpad.net/percona-toolkit/+bug/821690
is(
$qr->distill("DROP TABLE IF EXISTS foo"),
"DROP TABLE foo",
"distill DROP TABLE IF EXISTS foo (bug 821690)"
);
is(
$qr->distill("CREATE TABLE IF NOT EXISTS foo"),
"CREATE TABLE foo",
"distill CREATE TABLE IF NOT EXISTS foo",
);
$qr = new QueryRewriter(
QueryParser => $qp,
match_embedded_numbers => 1,
);
is(
$qr->fingerprint(
"SELECT * FROM prices2.t1 where id=1"
),
"select * from prices2.t1 where id=?",
"Fingerprint db.tbl<number>name (preserve number)"
);
is(
$qr->fingerprint(
"SELECT i FROM d.t WHERE i=\"3\""
),
"select i from d.t where i=?",
"Fingerprint db.tbl<number>name (preserve number)"
);
is(
$qr->fingerprint("CALL foo(1, 2, 3)"),
"call foo",
'Fingerprints stored procedure calls specially',
);
# #############################################################################
# Done.
# #############################################################################
done_testing;