#!/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;