Files
percona-toolkit/t/lib/MySQLProtocolParser.t
2016-12-16 22:38:15 -03:00

1859 lines
55 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 ProtocolParser;
use MySQLProtocolParser;
use TcpdumpParser;
use PerconaTest;
my $sample = "t/lib/samples/tcpdump";
my $tcpdump = new TcpdumpParser();
my $protocol; # Create a new MySQLProtocolParser for each test.
# Check that I can parse a really simple session.
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump001.txt",
result => [
{ ts => '090412 09:50:16.805123',
db => undef,
user => undef,
Thread_id => 4294967296,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '42167',
arg => 'select "hello world" as greeting',
Query_time => sprintf('%.6f', .805123 - .804849),
pos_in_log => 0,
bytes => length('select "hello world" as greeting'),
cmd => 'Query',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
],
);
$protocol = new MySQLProtocolParser(port=>3307);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump-1402776.txt",
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.001271',
Rows_affected => 0,
Thread_id => 3826,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => '',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '38784',
pos_in_log => 2011,
ts => '161215 17:07:52.041966',
user => 'root'
}
],
);
# A more complex session with a complete login/logout cycle.
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump002.txt",
result => [
{ ts => "090412 11:00:13.118191",
db => 'mysql',
user => 'msandbox',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
arg => 'administrator command: Connect',
Query_time => '0.011152',
Thread_id => 8,
pos_in_log => 1470,
bytes => length('administrator command: Connect'),
cmd => 'Admin',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
{ Query_time => '0.000265',
Thread_id => 8,
arg => 'select @@version_comment limit 1',
bytes => length('select @@version_comment limit 1'),
cmd => 'Query',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 2449,
ts => '090412 11:00:13.118643',
user => 'msandbox',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
{ Query_time => '0.000167',
Thread_id => 8,
arg => 'select "paris in the the spring" as trick',
bytes => length('select "paris in the the spring" as trick'),
cmd => 'Query',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 3298,
ts => '090412 11:00:13.119079',
user => 'msandbox',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
{ Query_time => '0.000000',
Thread_id => 8,
arg => 'administrator command: Quit',
bytes => 27,
cmd => 'Admin',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => '4186',
ts => '090412 11:00:13.119487',
user => 'msandbox',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
],
);
# A session that has an error during login.
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump003.txt",
result => [
{ ts => "090412 12:41:46.357853",
db => '',
user => 'msandbox',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '44488',
arg => 'administrator command: Connect',
Query_time => '0.010753',
Thread_id => 9,
pos_in_log => 1455,
bytes => length('administrator command: Connect'),
cmd => 'Admin',
Error_no => 1045,
Error_msg => 'Access denied for user \'msandbox\'@\'localhost\' (using password: YES)',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
],
);
# A session that has an error executing a query
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump004.txt",
result => [
{ ts => "090412 12:58:02.036002",
db => undef,
user => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '60439',
arg => 'select 5 from foo',
Query_time => '0.000251',
Thread_id => 4294967296,
pos_in_log => 0,
bytes => length('select 5 from foo'),
cmd => 'Query',
Error_no => "1046",
Error_msg => 'No database selected',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
],
);
# A session that has a single-row insert and a multi-row insert
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump005.txt",
result => [
{
Rows_affected => 1,
Query_time => '0.000435',
Thread_id => 4294967296,
arg => 'insert into test.t values(1)',
bytes => 28,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '55300',
pos_in_log => '0',
ts => '090412 16:46:02.978340',
user => undef,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
{
Rows_affected => 2,
Query_time => '0.000565',
Thread_id => 4294967296,
arg => 'insert into test.t values(1),(2)',
bytes => 32,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '55300',
pos_in_log => '1033',
ts => '090412 16:46:20.245088',
user => undef,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
],
);
# A session that causes a slow query because it doesn't use an index.
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump006.txt",
result => [
{ ts => '100412 20:46:10.776899',
db => undef,
user => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '48259',
arg => 'select * from t',
Query_time => '0.000205',
Thread_id => 4294967296,
pos_in_log => 0,
bytes => length('select * from t'),
cmd => 'Query',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'Yes',
},
],
);
# A session that truncates an insert.
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump007.txt",
result => [
{ ts => '090412 20:57:22.798296',
db => undef,
user => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '38381',
arg => 'insert into t values(current_date)',
Query_time => '0.000020',
Thread_id => 4294967296,
pos_in_log => 0,
bytes => length('insert into t values(current_date)'),
cmd => 'Query',
Rows_affected => 1,
Warning_count => 1,
No_good_index_used => 'No',
No_index_used => 'No',
},
],
);
# #############################################################################
# Check the individual packet parsing subs.
# #############################################################################
is_deeply(
MySQLProtocolParser::parse_error_packet(load_data("t/lib/samples/mysql_proto_001.txt")),
{
errno => '1046',
sqlstate => '#3D000',
message => 'No database selected',
},
'Parse error packet'
);
is_deeply(
MySQLProtocolParser::parse_ok_packet('010002000100'),
{
affected_rows => 1,
insert_id => 0,
status => 2,
warnings => 1,
message => '',
},
'Parse ok packet'
);
is_deeply(
MySQLProtocolParser::parse_server_handshake_packet(load_data("t/lib/samples/mysql_proto_002.txt")),
{
thread_id => '9',
server_version => '5.0.67-0ubuntu6-log',
flags => {
CLIENT_COMPRESS => 1,
CLIENT_CONNECT_WITH_DB => 1,
CLIENT_FOUND_ROWS => 0,
CLIENT_IGNORE_SIGPIPE => 0,
CLIENT_IGNORE_SPACE => 0,
CLIENT_INTERACTIVE => 0,
CLIENT_LOCAL_FILES => 0,
CLIENT_LONG_FLAG => 1,
CLIENT_LONG_PASSWORD => 0,
CLIENT_MULTI_RESULTS => 0,
CLIENT_MULTI_STATEMENTS => 0,
CLIENT_NO_SCHEMA => 0,
CLIENT_ODBC => 0,
CLIENT_PROTOCOL_41 => 1,
CLIENT_RESERVED => 0,
CLIENT_SECURE_CONNECTION => 1,
CLIENT_SSL => 0,
CLIENT_TRANSACTIONS => 1,
}
},
'Parse server handshake packet'
);
is_deeply(
MySQLProtocolParser::parse_client_handshake_packet(load_data("t/lib/samples/mysql_proto_003.txt")),
{
db => 'mysql',
user => 'msandbox',
flags => {
CLIENT_COMPRESS => 0,
CLIENT_CONNECT_WITH_DB => 1,
CLIENT_FOUND_ROWS => 0,
CLIENT_IGNORE_SIGPIPE => 0,
CLIENT_IGNORE_SPACE => 0,
CLIENT_INTERACTIVE => 0,
CLIENT_LOCAL_FILES => 1,
CLIENT_LONG_FLAG => 1,
CLIENT_LONG_PASSWORD => 1,
CLIENT_MULTI_RESULTS => 1,
CLIENT_MULTI_STATEMENTS => 1,
CLIENT_NO_SCHEMA => 0,
CLIENT_ODBC => 0,
CLIENT_PROTOCOL_41 => 1,
CLIENT_RESERVED => 0,
CLIENT_SECURE_CONNECTION => 1,
CLIENT_SSL => 0,
CLIENT_TRANSACTIONS => 1,
},
},
'Parse client handshake packet'
);
is_deeply(
MySQLProtocolParser::parse_com_packet('0373686f77207761726e696e67738d2dacbc', 14),
{
code => '03',
com => 'COM_QUERY',
data => 'show warnings',
},
'Parse COM_QUERY packet'
);
# Test that we can parse with a non-standard port etc.
$protocol = new MySQLProtocolParser(
server => '192.168.1.1',
port => '3307',
);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump012.txt",
result => [
{ ts => '090412 09:50:16.805123',
db => undef,
user => undef,
Thread_id => 4294967296,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '42167',
arg => 'select "hello world" as greeting',
Query_time => sprintf('%.6f', .805123 - .804849),
pos_in_log => 0,
bytes => length('select "hello world" as greeting'),
cmd => 'Query',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
],
);
# #############################################################################
# Issue 447: MySQLProtocolParser does not handle old password algo or
# compressed packets
# #############################################################################
$protocol = new MySQLProtocolParser(
server => '10.55.200.15',
);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump013.txt",
desc => 'old password and compression',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.034355',
Rows_affected => 0,
Thread_id => 36947020,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => 'nepool_ftr',
host => '10.54.212.171',
ip => '10.54.212.171',
port => '49663',
pos_in_log => 1834,
ts => '090603 10:52:24.578817',
user => 'luck'
},
],
);
# Check in-stream compression detection.
$protocol = new MySQLProtocolParser(
server => '10.55.200.15',
);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump014.txt",
desc => 'in-stream compression detection',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.001375',
Rows_affected => 0,
Thread_id => 4294967296,
Warning_count => 0,
arg => 'show databases',
bytes => 14,
cmd => 'Query',
db => undef,
host => '10.54.212.171',
ip => '10.54.212.171',
port => '49663',
pos_in_log => 0,
ts => '090603 10:52:24.587685',
user => undef,
},
],
);
eval { require IO::Uncompress::Inflate; };
SKIP: {
skip "IO::Uncompress::Inflate not installed", 2 if $EVAL_ERROR;
# Check data decompression.
$protocol = new MySQLProtocolParser(
server => '127.0.0.1',
port => '12345',
);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump015.txt",
desc => 'compressed data',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.006415',
Rows_affected => 0,
Thread_id => 20,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '44489',
pos_in_log => 664,
ts => '090612 08:39:05.316805',
user => 'msandbox',
},
{
No_good_index_used => 'No',
No_index_used => 'Yes',
Query_time => '0.002884',
Rows_affected => 0,
Thread_id => 20,
Warning_count => 0,
arg => 'select * from help_relation',
bytes => 27,
cmd => 'Query',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '44489',
pos_in_log => 1637,
ts => '090612 08:39:08.428913',
user => 'msandbox',
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000000',
Rows_affected => 0,
Thread_id => 20,
Warning_count => 0,
arg => 'administrator command: Quit',
bytes => 27,
cmd => 'Admin',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '44489',
pos_in_log => 15782,
ts => '090612 08:39:09.145334',
user => 'msandbox',
},
],
);
}
# TCP retransmission.
$protocol = new MySQLProtocolParser(
server => '10.55.200.15',
);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump016.txt",
desc => 'TCP retransmission',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.001000',
Rows_affected => 0,
Thread_id => 38559282,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => '',
host => '10.55.200.31',
ip => '10.55.200.31',
port => '64987',
pos_in_log => 468,
ts => '090609 16:53:17.112346',
user => 'ppppadri',
},
],
);
# #############################################################################
# Issue 537: MySQLProtocolParser and MemcachedProtocolParser do not handle
# multiple servers.
# #############################################################################
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump018.txt",
desc => 'Multiple servers',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000206',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'select * from foo',
bytes => 17,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '42275',
pos_in_log => 0,
ts => '090727 08:28:41.723651',
user => undef,
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000203',
Rows_affected => 0,
Thread_id => '4294967297',
Warning_count => 0,
arg => 'select * from bar',
bytes => 17,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '34233',
pos_in_log => 987,
ts => '090727 08:29:34.232748',
user => undef,
},
],
);
# Test that --watch-server causes just the given server to be watched.
$protocol = new MySQLProtocolParser(server=>'10.0.0.1',port=>'3306');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump018.txt",
desc => 'Multiple servers but watch only one',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000206',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'select * from foo',
bytes => 17,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '42275',
pos_in_log => 0,
ts => '090727 08:28:41.723651',
user => undef,
},
]
);
# #############################################################################
# Issue 558: Make mk-query-digest handle big/fragmented packets
# #############################################################################
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'12345');
my $e = test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump019.txt",
);
like(
$e->[0]->{arg},
qr/--THE END--'\)$/,
'Handles big, fragmented MySQL packets (issue 558)'
);
my $arg = load_file("$sample/tcpdump019-arg.txt");
chomp $arg;
is(
$e->[0]->{arg},
$arg,
'Re-assembled data is correct (issue 558)'
);
# #############################################################################
# Issue 740: Handle prepared statements
# #############################################################################
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'12345');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump021.txt",
desc => 'prepared statements, simple, no NULL',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000286',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SELECT i FROM d.t WHERE i=?',
bytes => 35,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '58619',
pos_in_log => 0,
ts => '091208 09:23:49.637394',
user => undef,
Statement_id => 2,
},
{
No_good_index_used => 'No',
No_index_used => 'Yes',
Query_time => '0.000281',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT i FROM d.t WHERE i="3"',
bytes => 37,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '58619',
pos_in_log => 1106,
ts => '091208 09:23:49.637892',
user => undef,
Statement_id => 2,
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000000',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'administrator command: Quit',
bytes => 27,
cmd => 'Admin',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '58619',
pos_in_log => 1850,
ts => '091208 09:23:49.638381',
user => undef
},
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'12345');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump022.txt",
desc => 'prepared statements, NULL value',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000303',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SELECT i,j FROM d.t2 WHERE i=? AND j=?',
bytes => 46,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '44545',
pos_in_log => 0,
ts => '091208 13:41:12.811188',
user => undef,
Statement_id => 2,
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000186',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT i,j FROM d.t2 WHERE i=NULL AND j="5"',
bytes => 51,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '44545',
pos_in_log => 1330,
ts => '091208 13:41:12.811591',
user => undef,
Statement_id => 2,
}
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'12345');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump023.txt",
desc => 'prepared statements, string, char and float',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000315',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SELECT * FROM d.t3 WHERE v=? OR c=? OR f=?',
bytes => 50,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '49806',
pos_in_log => 0,
ts => '091208 14:14:55.951863',
user => undef,
Statement_id => 2,
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000249',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT * FROM d.t3 WHERE v="hello world" OR c="a" OR f="1.23"',
bytes => 69,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '49806',
pos_in_log => 1540,
ts => '091208 14:14:55.952344',
user => undef,
Statement_id => 2,
}
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'12345');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump024.txt",
desc => 'prepared statements, all NULL',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000278',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SELECT * FROM d.t3 WHERE v=? OR c=? OR f=?',
bytes => 50,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '32810',
pos_in_log => 0,
ts => '091208 14:33:13.711351',
user => undef,
Statement_id => 2,
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000159',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT * FROM d.t3 WHERE v=NULL OR c=NULL OR f=NULL',
bytes => 59,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '32810',
pos_in_log => 1540,
ts => '091208 14:33:13.711642',
user => undef,
Statement_id => 2,
},
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'12345');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump025.txt",
desc => 'prepared statements, no params',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000268',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SELECT * FROM d.t WHERE 1 LIMIT 1;',
bytes => 42,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '48585',
pos_in_log => 0,
ts => '091208 14:44:52.709181',
user => undef,
Statement_id => 2,
},
{
No_good_index_used => 'No',
No_index_used => 'Yes',
Query_time => '0.000234',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT * FROM d.t WHERE 1 LIMIT 1;',
bytes => 42,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '48585',
pos_in_log => 1014,
ts => '091208 14:44:52.709597',
user => undef,
Statement_id => 2,
}
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'3306');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump026.txt",
desc => 'prepared statements, close statement',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000000',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'DEALLOCATE PREPARE 50',
bytes => 21,
cmd => 'Query',
db => undef,
host => '1.2.3.4',
ip => '1.2.3.4',
port => '34162',
pos_in_log => 0,
ts => '091208 17:42:12.696547',
user => undef
}
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'3306');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump027.txt",
desc => 'prepared statements, reset statement',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000023',
Rows_affected => 0,
Statement_id => 51,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'RESET 51',
bytes => 8,
cmd => 'Query',
db => undef,
host => '1.2.3.4',
ip => '1.2.3.4',
port => '34162',
pos_in_log => 0,
ts => '091208 17:42:12.698093',
user => undef
}
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'12345');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump028.txt",
desc => 'prepared statements, multiple exec, new param',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000292',
Rows_affected => 0,
Statement_id => 2,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SELECT * FROM d.t WHERE i=?',
bytes => 35,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '38682',
pos_in_log => 0,
ts => '091208 17:35:37.433248',
user => undef
},
{
No_good_index_used => 'No',
No_index_used => 'Yes',
Query_time => '0.000254',
Rows_affected => 0,
Statement_id => 2,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT * FROM d.t WHERE i="1"',
bytes => 37,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '38682',
pos_in_log => 1106,
ts => '091208 17:35:37.433700',
user => undef
},
{
No_good_index_used => 'No',
No_index_used => 'Yes',
Query_time => '0.000190',
Rows_affected => 0,
Statement_id => 2,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT * FROM d.t WHERE i="3"',
bytes => 37,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '38682',
pos_in_log => 1850,
ts => '091208 17:35:37.434303',
user => undef
},
{
No_good_index_used => 'No',
No_index_used => 'Yes',
Query_time => '0.000166',
Rows_affected => 0,
Statement_id => 2,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT * FROM d.t WHERE i=NULL',
bytes => 38,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '38682',
pos_in_log => 2589,
ts => '091208 17:35:37.434708',
user => undef
}
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'12345');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump029.txt",
desc => 'prepared statements, real param types',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000221',
Rows_affected => 0,
Statement_id => 1,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SELECT * FROM d.t WHERE i=? OR u=? OR v=? OR d=? OR f=? OR t > ? OR dt > ?',
bytes => 82,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '36496',
pos_in_log => 0,
ts => '091209 09:20:59.293775',
user => undef
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000203',
Rows_affected => 0,
Statement_id => 1,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT * FROM d.t WHERE i=42 OR u=2009 OR v="hello world" OR d=1.23 OR f=4.56 OR t > "2009-12-01" OR dt > "2009-12-01"',
bytes => 126,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '36496',
pos_in_log => 2109,
ts => '091209 09:20:59.294409',
user => undef
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000000',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'DEALLOCATE PREPARE 1',
bytes => 20,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '36496',
pos_in_log => 3787,
ts => '091209 09:20:59.294926',
user => undef
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000000',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'administrator command: Quit',
bytes => 27,
cmd => 'Admin',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '36496',
pos_in_log => 4051,
ts => '091209 09:20:59.295064',
user => undef
},
]
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'3306');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump030.txt",
desc => 'prepared statements, ok response to execute',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000046',
Rows_affected => 0,
Statement_id => 1,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SET SESSION sql_mode="STRICT_ALL_TABLES"',
bytes => 48,
cmd => 'Query',
db => undef,
host => '1.2.3.24',
ip => '1.2.3.24',
port => '60696',
pos_in_log => 0,
ts => '091210 14:21:16.956302',
user => undef
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000024',
Rows_affected => 0,
Statement_id => 1,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SET SESSION sql_mode="STRICT_ALL_TABLES"',
bytes => 48,
cmd => 'Query',
db => undef,
host => '1.2.3.24',
ip => '1.2.3.24',
port => '60696',
pos_in_log => 700,
ts => '091210 14:21:16.956446',
user => undef
}
],
);
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'3306');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump034.txt",
desc => 'prepared statements, NULL bitmap',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000288',
Rows_affected => 0,
Statement_id => 1,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'PREPARE SELECT * FROM d.t WHERE i=? OR u=? OR v=? OR d=? OR f=? OR t > ? OR dt > ? OR i2=? OR i3=? OR i4=?',
bytes => 106,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '43607',
pos_in_log => 0,
ts => '091224 16:47:24.204501',
user => undef
},
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000322',
Rows_affected => 0,
Statement_id => 1,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'EXECUTE SELECT * FROM d.t WHERE i=42 OR u=2009 OR v="hello world" OR d=1.23 OR f=4.56 OR t > "2009-12-01" OR dt > "2009-12-01" OR i2=NULL OR i3=NULL OR i4=NULL',
bytes => 159,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '43607',
pos_in_log => 2748,
ts => '091224 16:47:24.204965',
user => undef
}
],
);
# #############################################################################
# Issue 761: mk-query-digest --tcpdump does not handle incomplete packets
# #############################################################################
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'3306');
$protocol->{_no_save_error} = 1;
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump032.txt",
desc => 'issue 761',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000431',
Rows_affected => 1,
Thread_id => '4294967296',
Warning_count => 21032,
arg => 'UPDATEDDDDNNNN',
bytes => 14,
cmd => 'Query',
db => undef,
host => '1.2.3.4',
ip => '1.2.3.4',
port => '35957',
pos_in_log => 1768,
ts => '091208 20:54:54.795250',
user => undef
}
],
);
# #############################################################################
# Issue 760: mk-query-digest --tcpdump might not get the whole query
# #############################################################################
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'3306');
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump031.txt",
desc => 'issue 760',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000430',
Rows_affected => 1,
Thread_id => '4294967296',
Warning_count => 21032,
arg => 'UPDATEDDDDNNNN',
bytes => 14,
cmd => 'Query',
db => undef,
host => '1.2.3.4',
ip => '1.2.3.4',
port => '35957',
pos_in_log => 534,
ts => '091207 20:54:54.795250',
user => undef
}
],
);
# #############################################################################
# Issue 794: MySQLProtocolParser does not handle client port reuse
# #############################################################################
$protocol = new MySQLProtocolParser();
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump035.txt",
desc => 'client port reuse (issue 794)',
result => [
{ ts => "090412 11:00:13.118191",
db => 'mysql',
user => 'msandbox',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
arg => 'administrator command: Connect',
Query_time => '0.011152',
Thread_id => 8,
pos_in_log => 1470,
bytes => length('administrator command: Connect'),
cmd => 'Admin',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
{ Query_time => '0.000167',
Thread_id => 8,
arg => 'select "paris in the the spring" as trick',
bytes => length('select "paris in the the spring" as trick'),
cmd => 'Query',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 2449,
ts => '090412 11:00:13.119079',
user => 'msandbox',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
{ Query_time => '0.000000',
Thread_id => 8,
arg => 'administrator command: Quit',
bytes => 27,
cmd => 'Admin',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 3337,
ts => '090412 11:00:13.119487',
user => 'msandbox',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
# port reused...
{ ts => '090412 12:00:00.800000',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.700000',
Rows_affected => 0,
Thread_id => 8,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 5791,
user => 'msandbox',
},
{ ts => '090412 12:00:01.000000',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.100000',
Rows_affected => 0,
Thread_id => 8,
Warning_count => 0,
arg => 'select "paris in the the spring" as trick',
bytes => 41,
cmd => 'Query',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 6770,
user => 'msandbox',
},
{ ts => '090412 12:00:01.100000',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000000',
Rows_affected => 0,
Thread_id => 8,
Warning_count => 0,
arg => 'administrator command: Quit',
bytes => 27,
cmd => 'Admin',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 7658,
user => 'msandbox',
}
],
);
$protocol = new MySQLProtocolParser();
$protocol->{_no_save_error} = 1;
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump036.txt",
desc => 'Houdini data (issue 794)',
result => [
{ ts => "090412 11:00:13.118191",
db => 'mysql',
user => 'msandbox',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
arg => 'administrator command: Connect',
Query_time => '0.011152',
Thread_id => 8,
pos_in_log => 1470,
bytes => length('administrator command: Connect'),
cmd => 'Admin',
Rows_affected => 0,
Warning_count => 0,
No_good_index_used => 'No',
No_index_used => 'No',
},
# port reused...
{ ts => '090412 12:00:00.800000',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.700000',
Rows_affected => 0,
Thread_id => 8,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 4161,
user => 'msandbox',
},
{ ts => '090412 12:00:01.000000',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.100000',
Rows_affected => 0,
Thread_id => 8,
Warning_count => 0,
arg => 'select "paris in the the spring" as trick',
bytes => 41,
cmd => 'Query',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 5140,
user => 'msandbox',
},
{ ts => '090412 12:00:01.100000',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000000',
Rows_affected => 0,
Thread_id => 8,
Warning_count => 0,
arg => 'administrator command: Quit',
bytes => 27,
cmd => 'Admin',
db => 'mysql',
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 6028,
user => 'msandbox',
}
],
);
$protocol = new MySQLProtocolParser();
$protocol->{_no_save_error} = 1;
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump037.txt",
desc => 'no server ok (issue 794)',
result => [
{ ts => '090412 12:00:01.000000',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000000',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'administrator command: Quit',
bytes => 27,
cmd => 'Admin',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 390,
user => undef
},
{ ts => '090412 12:00:03.000000',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '1.000000',
Rows_affected => 0,
Thread_id => 4294967297,
Warning_count => 0,
arg => 'select "paris in the the spring" as trick',
bytes => 41,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '57890',
pos_in_log => 646,
user => undef,
},
],
);
# #############################################################################
# Issue 832: mk-query-digest tcpdump crashes on successive, fragmented
# client query
# #############################################################################
$protocol = new MySQLProtocolParser(server => '127.0.0.1',port=>'12345');
$protocol->{_no_save_error} = 1;
$e = test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump038.txt",
);
like(
$e->[0]->{arg},
qr/--THE END--'\)$/,
'2nd, fragmented client query (issue 832)',
);
# #############################################################################
# Issue 670: Make mk-query-digest capture the error message from tcpdump
# #############################################################################
$protocol = new MySQLProtocolParser(
server => '127.0.0.1',
port => '3306',
);
$protocol->{_no_save_error} = 1;
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump040.txt",
desc => 'Error (issue 670)',
result =>
[
{
Error_msg => "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1",
Error_no => '1064',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000316',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'select',
bytes => 6,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '39640',
pos_in_log => 0,
ts => '091101 14:54:44.293453',
user => undef,
},
{
Error_msg => 'Unknown system variable \'nono\'',
Error_no => '1193',
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '0.000329',
Rows_affected => 0,
Thread_id => '4294967296',
Warning_count => 0,
arg => 'set global nono = 2',
bytes => 19,
cmd => 'Query',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '39640',
pos_in_log => 1250,
ts => '091101 14:54:52.813941',
user => undef,
},
],
);
# #############################################################################
# Bug 1103045: pt-query-digest fails to parse non-SQL errors
# https://bugs.launchpad.net/percona-toolkit/+bug/1103045
# #############################################################################
$protocol = new MySQLProtocolParser(
server => '127.0.0.1',
port => '12345',
);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump043.txt",
desc => 'Bad connection',
result =>
[
{
Error_msg => 'Got packets out of order',
Error_no => 1156,
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '3.536306',
Rows_affected => 0,
Thread_id => 27,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '62160',
pos_in_log => undef,
ts => '130124 13:03:28.672987',
user => undef,
}
],
);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump042.txt",
desc => 'Client went away during handshake',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '9.998411',
Rows_affected => 0,
Thread_id => 24,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => undef,
host => '127.0.0.1',
ip => '127.0.0.1',
port => '62133',
pos_in_log => undef,
ts => '130124 12:55:48.274417',
user => undef,
Error_msg => 'Client closed connection during handshake',
}
],
);
$protocol = new MySQLProtocolParser(
server => '100.0.0.1',
);
test_protocol_parser(
parser => $tcpdump,
protocol => $protocol,
file => "$sample/tcpdump044.txt",
desc => 'Client aborted connection (bug 1103045)',
result => [
{
No_good_index_used => 'No',
No_index_used => 'No',
Query_time => '3.819507',
Rows_affected => 0,
Thread_id => 13,
Warning_count => 0,
arg => 'administrator command: Connect',
bytes => 30,
cmd => 'Admin',
db => undef,
host => '100.0.0.2',
ip => '100.0.0.2',
port => '44432',
pos_in_log => undef,
ts => '130122 09:55:57.793375',
user => undef,
Error_msg => 'Client closed connection during handshake',
},
],
);
# #############################################################################
# Save errors by default
# #############################################################################
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'3306');
my $out = output(sub {
open my $fh, "<", "$sample/tcpdump032.txt" or die "Cannot open tcpdump032.txt: $OS_ERROR";
my %parser_args = (
next_event => sub { return <$fh>; },
tell => sub { return tell($fh); },
);
while ( my $p = $tcpdump->parse_event(%parser_args) ) {
$protocol->parse_event(%parser_args, event => $p);
}
close $fh;
}, stderr => 1);
like(
$out,
qr/had errors, will save them in /,
"Saves errors by default"
);
close $protocol->{errors_fh}; # flush the handle
like(
slurp_file($protocol->{errors_file}),
qr/got server response before full buffer/,
"The right error is saved"
);
$out = output(sub {
open my $fh, "<", "$sample/tcpdump032.txt" or die "Cannot open tcpdump032.txt: $OS_ERROR";
my %parser_args = (
next_event => sub { return <$fh>; },
tell => sub { return tell($fh); },
);
while ( my $p = $tcpdump->parse_event(%parser_args) ) {
$protocol->parse_event(%parser_args, event => $p);
}
close $fh;
}, stderr => 1);
is(
$out,
'',
"No warnings the second time around"
);
{
$protocol = new MySQLProtocolParser(server=>'127.0.0.1',port=>'3306');
# ..but allow setting the filename through an ENV var:
local $ENV{PERCONA_TOOLKIT_TCP_ERRORS_FILE} = '/dev/null';
$out = output(sub {
open my $fh, "<", "$sample/tcpdump032.txt" or die "Cannot open tcpdump032.txt: $OS_ERROR";
my %parser_args = (
next_event => sub { return <$fh>; },
tell => sub { return tell($fh); },
);
while ( my $p = $tcpdump->parse_event(%parser_args) ) {
$protocol->parse_event(%parser_args, event => $p);
}
close $fh;
}, stderr => 1);
like(
$out,
qr/had errors, will save them in /,
"Still tries saving the errors with PERCONA_TOOLKIT_TCP_ERRORS_FILE"
);
is(
$protocol->{errors_file},
'/dev/null',
"...but uses the provided file"
);
}
# #############################################################################
# Done.
# #############################################################################
# Get rid of error files
`rm /tmp/MySQLProtocolParser.t-errors.*`;
done_testing;