File Coverage

blib/lib/Net/Wire10.pm
Criterion Covered Total %
statement 152 1035 14.6
branch 4 370 1.0
condition 0 66 0.0
subroutine 42 141 29.7
pod 12 12 100.0
total 210 1624 12.9


line stmt bran cond sub pod time code
1             package Net::Wire10;
2              
3 1     1   25423 use strict;
  1         2  
  1         39  
4 1     1   5 use warnings;
  1         2  
  1         28  
5 1     1   929 use IO::Socket;
  1         166232  
  1         5  
6 1     1   1531 use IO::Select;
  1         1921  
  1         44  
7 1     1   952 use utf8;
  1         10  
  1         10  
8 1     1   1005 use Encode;
  1         86939  
  1         196  
9 1     1   12 use vars qw($VERSION $DEBUG);
  1         3  
  1         71  
10              
11             use constant {
12 1         100 DEFAULT_PORT_NUMBER => 3306,
13             DEFAULT_CONNECT_TIMEOUT => 5,
14             DEFAULT_QUERY_TIMEOUT => 30,
15 1     1   5 };
  1         3  
16              
17             $VERSION = '1.08';
18              
19 1     1   4 use constant STREAM_BUFFER_LENGTH => 65536;
  1         3  
  1         217  
20 1     1   5 use constant MACKET_HEADER_LENGTH => 4;
  1         1  
  1         40  
21 1     1   5 use constant TIMEOUT_GRANULARITY => 1;
  1         2  
  1         2332  
22              
23             BEGIN {
24             package Net::Wire10;
25              
26             # Macket (MySQL messages) types.
27 1     1   10 our %MACKET_NAMES = (
28             1 => 'HANDSHAKE',
29             2 => 'AUTHENTICATE',
30             4 => 'OK',
31             8 => 'ERROR',
32             16 => 'COMMAND',
33             32 => 'RESULT_SET_HEADER',
34             64 => 'COLUMN_INFO',
35             128 => 'EOF',
36             256 => 'ROW_DATA',
37             512 => 'MORE_DATA',
38             );
39              
40             # Type of commands that can be sent to the server.
41             # Only QUIT, QUERY and PING are currently used.
42 1         23 our %COMMAND_NAMES = (
43             "\x00" => 'SLEEP',
44             "\x01" => 'QUIT',
45             "\x02" => 'INIT_DB',
46             "\x03" => 'QUERY',
47             "\x04" => 'FIELD_LIST',
48             "\x05" => 'CREATE_DB',
49             "\x06" => 'DROP_DB',
50             "\x07" => 'REFRESH',
51             "\x08" => 'SHUTDOWN',
52             "\x09" => 'STATISTICS',
53             "\x0A" => 'PROCESS_INFO',
54             "\x0B" => 'CONNECT',
55             "\x0C" => 'PROCESS_KILL',
56             "\x0D" => 'DEBUG',
57             "\x0E" => 'PING',
58             "\x0F" => 'TIME',
59             "\x10" => 'DELAYED_INSERT',
60             "\x11" => 'CHANGE_USER',
61             "\x12" => 'BINLOG_DUMP',
62             "\x13" => 'TABLE_DUMP',
63             "\x14" => 'CONNECT_OUT',
64             "\x15" => 'REGISTER_SLAVE',
65             "\x16" => 'STMT_PREPARE',
66             "\x17" => 'STMT_EXECUTE',
67             "\x18" => 'STMT_SEND_LONG_DATA',
68             "\x19" => 'STMT_CLOSE',
69             "\x1A" => 'STMT_RESET',
70             "\x1B" => 'SET_OPTION',
71             "\x1C" => 'STMT_FETCH',
72             "\x1D" => 'DAEMON',
73             );
74              
75             # Per-connection flags, some of which are sent to the
76             # server during handshake to convey client capabilities.
77 1         14 our %FLAG_NAMES = (
78             0x00000001 => 'LONG_PASSWORD',
79             0x00000002 => 'FOUND_ROWS',
80             0x00000004 => 'LONG_FLAG',
81             0x00000008 => 'CONNECT_WITH_DB',
82             0x00000010 => 'NO_SCHEMA',
83             0x00000020 => 'COMPRESS',
84             0x00000040 => 'ODBC',
85             0x00000080 => 'LOCAL_FILES',
86             0x00000100 => 'IGNORE_SPACE',
87             0x00000200 => 'PROTOCOL_41',
88             0x00000400 => 'INTERACTIVE',
89             0x00000800 => 'SSL',
90             0x00001000 => 'IGNORE_SIGPIPE',
91             0x00002000 => 'TRANSACTIONS',
92             0x00004000 => 'RESERVED',
93             0x00008000 => 'SECURE_CONNECTION',
94             0x00010000 => 'MULTI_STATEMENTS',
95             0x00020000 => 'MULTI_RESULTS',
96             0x40000000 => 'SSL_VERIFY_SERVER_CERT',
97             0x80000000 => 'REMEMBER_OPTIONS',
98             );
99              
100 1         40 our %UTF8_COLLATIONS = (
101             33 => 'GENERAL_CI',
102             83 => 'BIN',
103             192 => 'UNICODE_CI',
104             193 => 'ICELANDIC_CI',
105             194 => 'LATVIAN_CI',
106             195 => 'ROMANIAN_CI',
107             196 => 'SLOVENIAN_CI',
108             197 => 'POLISH_CI',
109             198 => 'ESTONIAN_CI',
110             199 => 'SPANISH_CI',
111             200 => 'SWEDISH_CI',
112             201 => 'TURKISH_CI',
113             202 => 'CZECH_CI',
114             203 => 'DANISH_CI',
115             204 => 'LITHUANIAN_CI',
116             205 => 'SLOVAK_CI',
117             206 => 'SPANISH2_CI',
118             207 => 'ROMAN_CI',
119             208 => 'PERSIAN_CI',
120             209 => 'ESPERANTO_CI',
121             210 => 'HUNGARIAN_CI',
122             );
123              
124 1         3 our %DATA_TYPES = (
125             0 => 'TEXT',
126             1 => 'BINARY',
127             );
128              
129 1         8 our %SERVER_STATUS = (
130             0x00000001 => 'IN_TRANS',
131             0x00000002 => 'AUTOCOMMIT',
132             0x00000004 => 'MORE_RESULTS',
133             0x00000008 => 'MORE_RESULTS_EXISTS',
134             0x00000010 => 'NO_GOOD_INDEX_USED',
135             0x00000020 => 'NO_INDEX_USED',
136             0x00000040 => 'CURSOR_EXISTS',
137             0x00000080 => 'LAST_ROW_SENT',
138             0x00000100 => 'DB_DROPPED',
139             0x00000200 => 'NO_BACKSLASH_ESCAPES',
140             0x00000400 => 'METADATA_CHANGED',
141             );
142              
143 1         22 our %COLUMN_TYPES = (
144             0 => 'DECIMAL',
145             1 => 'TINY',
146             2 => 'SHORT',
147             3 => 'LONG',
148             4 => 'FLOAT',
149             5 => 'DOUBLE5',
150             6 => 'NULL',
151             7 => 'TIMESTAMP',
152             8 => 'LONGLONG',
153             9 => 'INT24',
154             10 => 'DATE',
155             11 => 'TIME',
156             12 => 'DATETIME',
157             13 => 'YEAR',
158             14 => 'NEWDATE',
159             15 => 'VARCHAR',
160             16 => 'BIT',
161             246 => 'NEWDECIMAL',
162             247 => 'ENUM',
163             248 => 'SET',
164             249 => 'TINY_BLOB',
165             250 => 'MEDIUM_BLOB',
166             251 => 'LONG_BLOB',
167             252 => 'BLOB',
168             253 => 'VAR_STRING',
169             254 => 'STRING',
170             255 => 'GEOMETRY',
171             );
172              
173 1         10 our %COLUMN_FLAGS = (
174             0x000001 => 'NOT_NULL', # Column has a NOT NULL constraint
175             # ... Skip flags that provide incomplete and/or ambiguous information under nearly all circumstances ...
176             # ... Skip deprecated flags ...
177             0x000020 => 'UNSIGNED', # Column data type is unsigned
178             0x000040 => 'ZEROFILL', # Column was created with the ZEROFILL flag
179             # ... Skip deprecated flags ...
180             0x000200 => 'AUTO_INCREMENT', # Default field values for this column are generated by a thread-safe sequencer
181             # ... Skip deprecated flags ...
182             0x001000 => 'NO_DEFAULT_VALUE', # Column does not have a default value
183             0x002000 => 'ON_UPDATE_NOW', # Column default value is NOW() when an UPDATE affects the column
184             # ... Skip deprecated flags, internal and temporary flags ...
185             );
186              
187             # Enumerations that are currently not included here:
188             # * Server capabilities
189             # * Server language
190             # * Server error code
191             # * Server error state
192             # * Column flags (complete)
193             # * Collations (complete)
194              
195             # TODO: An enumeration with a 2xxx error code for each client-side error.
196              
197             sub _assign {
198 1     1   6 no strict 'refs';
  1         2  
  1         594  
199 130     130   209 my $pkg = caller() . '::';
200 130         173 my $key = shift;
201 130         154 my $value = shift;
202 130     0   7191 *{"$pkg$key"} = sub () { $value };
  130         18787  
  0         0  
203             }
204              
205             sub _make_constant {
206 8     8   11 my $what = shift;
207 8         10 my $prefix = shift;
208 8         11 my $i = 0;
209 8         32 while ((my $key, my $value) = each(%$what)) {
210 127         2477 _assign("$prefix$value", $key);
211             }
212             }
213              
214             sub _find_largest_uint {
215             # Assumes the Perl compiler uses signed integers.
216 1     1   1 my $cur = 0;
217 1         2 my $next = 0;
218 1         7 for (my $i = 0; $i <= 16; $i++) {
219 8         12 $next += (0xff << ($i * 8));
220 8 100       27 return $i if sprintf("%d", $next) < 0;
221 7         16 $cur = $next;
222             }
223             }
224              
225             sub _detect_alarm_bug {
226             # Try for 2sec to activate a 1sec (potentially less)
227             # alarm(), while cycling through select(). During
228             # package construction, this takes 0.1s if bug-free
229             # and ~2s otherwise.
230 0     0   0 my $alarm_bug = 1;
231 0     0   0 local $SIG{ALRM} = sub { $alarm_bug = 0; };
  0         0  
232 0         0 alarm 1;
233 0         0 for (my $i = 0; $i < 20; $i++) {
234 0 0       0 last if $alarm_bug == 0;
235 0         0 select(undef, undef, undef, 0.1);
236             }
237 0     0   0 local $SIG{ALRM} = sub { };
  0         0  
238 0         0 sleep 0;
239 0         0 return $alarm_bug;
240             }
241              
242             sub _flags_included {
243 1     1   2 my $flags = shift;
244 1         1 my $i = 0;
245 1         5 while ((my $key, my $value) = each(%$flags)) {
246 6         87 $i |= $key;
247             }
248 1         4 return $i;
249             }
250              
251 1         3 _assign("MAX_UINT_SIZE", _find_largest_uint);
252 1         3 _assign("USEFUL_COLUMN_FLAGS", _flags_included(\%COLUMN_FLAGS));
253              
254             # Pick your poison.. Detecting whether the current platform has
255             # this bug takes 1-2 seconds if the bug is present; always
256             # activating the workaround introduces an (as yet) unmeasured
257             # delay on platforms where the bug is not present; activating
258             # the workaround based on a platform identifier does not adapt
259             # when a new platform appears or an old platform gets fixed.
260             #
261             #_assign("FIX_ALARM_BUG", _detect_alarm_bug);
262             #_assign("FIX_ALARM_BUG", 1);
263 1 50       6 _assign("FIX_ALARM_BUG", $^O =~ /^MSWin/ ? 1 : 0);
264              
265 1         3 _make_constant(\%MACKET_NAMES, "MACKET_");
266 1         2 _make_constant(\%COMMAND_NAMES, "COMMAND_");
267 1         3 _make_constant(\%FLAG_NAMES, "FLAG_");
268 1         4 _make_constant(\%UTF8_COLLATIONS, "UTF8_");
269 1         2 _make_constant(\%DATA_TYPES, "DATA_");
270 1         3 _make_constant(\%SERVER_STATUS, "STATUS_");
271 1         9 _make_constant(\%COLUMN_TYPES, "TYPE_");
272 1         10 _make_constant(\%COLUMN_FLAGS, "COLUMN_");
273             }
274              
275             my %MACKET_NAMES = %{*MACKET_NAMES};
276             my %COMMAND_NAMES = %{*COMMAND_NAMES};
277             my %FLAG_NAMES = %{*FLAG_NAMES};
278             my %UTF8_COLLATIONS = %{*UTF8_COLLATIONS};
279             my %DATA_TYPES = %{*DATA_TYPES};
280             my %SERVER_STATUS = %{*SERVER_STATUS};
281             my %COLUMN_TYPES = %{*COLUMN_TYPES};
282             my %COLUMN_FLAGS = %{*COLUMN_FLAGS};
283              
284             # Constructor
285             sub new {
286 0     0 1   my $class = shift;
287 0           my %args = @_;
288              
289 0 0 0       my $self = bless {
    0 0        
      0        
290             host => $args{host},
291             port => $args{port} || DEFAULT_PORT_NUMBER,
292             database => $args{database},
293             user => $args{user},
294             password => $args{password},
295             connect_timeout => defined($args{connect_timeout}) ? $args{connect_timeout} : DEFAULT_CONNECT_TIMEOUT,
296             query_timeout => defined($args{query_timeout}) ? $args{query_timeout} : DEFAULT_QUERY_TIMEOUT,
297             flags => $args{flags} || 0,
298             debug => $args{debug} || 0,
299             }, $class;
300 0           $self->_reset_connection_state;
301 0           $self->_reset_command_state;
302 0           return $self;
303             }
304              
305             # Initializes the connection to the server.
306             # An error is raised by an inner class if already connected
307             sub connect {
308 0     0 1   my $self = shift;
309 0           $self->_connect;
310 0           $self->_perform_handshake;
311 0           $self->_perform_authentication;
312             }
313              
314             # Sends an SQL query
315             sub query {
316 0     0 1   my $self = shift;
317 0           my $sql = shift;
318              
319 0           return $self->_execute_query($sql, 0);
320             }
321              
322             # Sends an SQL query, but does not read any rows in the result set
323             sub stream {
324 0     0 1   my $self = shift;
325 0           my $sql = shift;
326              
327 0           return $self->_execute_query($sql, 1);
328             }
329              
330             # Creates a prepared statement object.
331             sub prepare {
332 0     0 1   my $self = shift;
333 0           my $sql = shift;
334              
335 0           return Net::Wire10::PreparedStatement->new($self, $sql);
336             }
337              
338             # Sends a wire protocol ping
339             sub ping {
340 0     0 1   my $self = shift;
341              
342 0           $self->_check_streaming;
343 0           $self->_check_connected;
344 0           $self->_reset_command_state;
345 0           $self->_reset_timeout($self->{connect_timeout});
346              
347 0           return $self->_execute_command(COMMAND_PING, '', undef);
348             }
349              
350             # Close the database connection
351             sub disconnect {
352 0     0 1   my $self = shift;
353 0           my $socket = $self->{socket};
354 0           my $select = $self->{io_select};
355              
356 0           eval {
357 0 0         if ($socket) {
358 0 0         if ($select) {
359 0 0         if ($select->can_write(TIMEOUT_GRANULARITY)) {
360 0           my $body = COMMAND_QUIT;
361 0           $self->_send_mackets($body, 0, MACKET_COMMAND);
362             }
363             }
364 0           $socket->close;
365             }
366             };
367 0 0         warn $@ if $@;
368              
369 0           $self->_reset_command_state;
370 0           $self->_reset_connection_state;
371              
372 0           return undef;
373             }
374              
375             # Cancels a running query
376             sub cancel {
377 0     0 1   my $self = shift;
378 0           $self->{cancelling} = 1;
379 0           return undef;
380             }
381              
382             # Get the connection id
383             sub get_connection_id {
384 0     0 1   my $self = shift;
385 0           return $self->{server_thread_id};
386             }
387              
388             # Get the server version string
389             sub get_server_version {
390 0     0 1   my $self = shift;
391 0           return $self->{server_version};
392             }
393              
394             # Is the driver currently connected?
395             # If a fatal error has occurred, this will return false
396             sub is_connected {
397 0     0 1   my $self = shift;
398 0           return defined($self->{socket});
399             }
400              
401             # Return the current error object, if any
402             sub get_error_info {
403 0     0 1   my $self = shift;
404 0           return $self->{error};
405             }
406              
407             # Reset the time remaining counter before executing a command
408             sub _reset_timeout {
409 0     0     my $self = shift;
410 0           my $seconds = shift;
411 0 0         if ($seconds == 0) {
412 0           $self->{command_expire_time} = 0;
413 0           return undef;
414             }
415 0           $self->{command_expire_time} = time + $seconds;
416 0           return undef;
417             }
418              
419             # Return the number of seconds left before the current
420             # operation should time out
421             sub _check_time_remaining {
422 0     0     my $self = shift;
423 0 0         return 0 if $self->{command_expire_time} == 0;
424 0           my $remaining = $self->{command_expire_time} - time;
425 0 0         $self->_fatal_error("Timeout while receiving data") if $remaining < 1;
426 0           return $remaining;
427             }
428              
429             # Fail if not connected anymore, due for example to a fatal error
430             sub _check_connected {
431 0     0     my $self = shift;
432 0 0         $self->_fatal_error("Not connected") unless defined($self->{socket});
433             }
434              
435             # Fail if currently connected to a streaming data reader
436             sub _check_streaming {
437 0     0     my $self = shift;
438 0 0         $self->_vanilla_error("Connection is busy streaming") if $self->{streaming};
439             }
440              
441             # Connects to the database server
442             sub _connect {
443 0     0     my $self = shift;
444              
445 0 0         $self->_vanilla_error("Already connected") if defined($self->{socket});
446 0 0         $self->_fatal_error("No host given") if length($self->{host}) == 0;
447 0 0         $self->_fatal_error("No port given") if length($self->{port}) == 0;
448              
449             # Connect timeout.
450 0           $self->_reset_timeout($self->{connect_timeout});
451              
452 0           my $socket;
453 0 0         printf "Connecting to: %s:%d/tcp\n", $self->{host}, $self->{port} if $self->{debug} & 1;
454 0 0         $socket = IO::Socket::INET->new(
455             Proto => 'tcp',
456             PeerAddr => $self->{host},
457             PeerPort => $self->{port},
458             Timeout => $self->_check_time_remaining
459             ) or $self->_fatal_error("Couldn't connect to $self->{host}:$self->{port}/tcp: $@");
460 0           $socket->autoflush(1);
461 0           $socket->timeout(TIMEOUT_GRANULARITY);
462 0           $self->{socket} = $socket;
463 0           $self->{io_select} = new IO::Select($self->{socket});
464              
465 0           $self->_reset_command_state;
466             }
467              
468             # When a fatal error occurs, tear down TCP
469             # connection and set command state to indicate error.
470             sub _fatal_error {
471 0     0     my $self = shift;
472 0   0       my $msg = shift || '';
473              
474 0           $self->disconnect;
475              
476 0 0         $self->{error} = Net::Wire10::Error->new(-1, '', $msg) unless defined ($self->{error});
477 0 0         $self->{error}->{message} = $msg if length($msg) > 0;
478              
479 0           die $self->{error}->{message};
480             }
481              
482             # When a non-fatal error occurs, just throw it.
483             sub _vanilla_error {
484 0     0     my $self = shift;
485 0   0       my $msg = shift || '';
486              
487 0 0         $self->{error} = Net::Wire10::Error->new(-1, '', $msg) unless defined ($self->{error});
488 0 0         $self->{error}->{message} = $msg if length($msg) > 0;
489              
490 0           die $self->{error}->{message};
491             }
492              
493             # Receives data from the network and reassembles fragmented packets
494             sub _receive_packet_data {
495 0     0     my $self = shift;
496 0           my $socket = $self->{socket};
497 0           my $io_select = $self->{io_select};
498 0           my $data;
499              
500 0           while ($self->_check_time_remaining) {
501             # Cancel if requested.
502 0 0         $self->_fatal_error("Query cancelled") if $self->{cancelling};
503             # Ask every second if there is data to be read.
504 0           my $ready = $io_select->can_read(TIMEOUT_GRANULARITY);
505             # IO::Select sometimes returns undef instead of an empty array.
506 0 0 0       last if defined($ready) && (scalar($ready) != 0);
507             # Work around a bug in alarm().
508 0           sleep 0 if FIX_ALARM_BUG;
509             }
510              
511 0           $socket->recv($data, STREAM_BUFFER_LENGTH, 0);
512             # If select said data is available, but it
513             # was not, it means the connection was lost.
514 0 0         $self->_fatal_error("Lost connection") if length($data) == 0;
515 0           $self->_dump_packet($data);
516              
517 0           $self->_alloc_packet_buffer(\$data);
518 0           $self->_add_to_packet_buffer(\$data);
519             }
520              
521             # If we have an idea of how much data is arriving, or there is not
522             # enough room for the recently received chunk, allocate more memory
523             sub _alloc_packet_buffer {
524 0     0     my $self = shift;
525 0           my $data = shift;
526              
527 0           my $buflen = length($self->{packet_buffer});
528 0 0         my $goal = defined($self->{packet_goal}) ? $self->{packet_goal} + MACKET_HEADER_LENGTH : 0;
529 0           my $goal2 = length($$data) + $self->{packet_read};
530 0 0         $goal = $goal2 if $goal2 > $goal;
531 0 0         if ($buflen < $goal ) {
532 0           $self->{packet_buffer} .= ' ' x ($goal - $buflen);
533             }
534             }
535              
536             # Add received data to packet buffer
537             sub _add_to_packet_buffer {
538 0     0     my $self = shift;
539 0           my $data = shift;
540 0           substr $self->{packet_buffer}, $self->{packet_read}, length($$data), $$data;
541 0           $self->{packet_read} += length($$data);
542             }
543              
544             # Queue the whole mackets received
545             sub _queue_mackets {
546 0     0     my $self = shift;
547 0           my $packet = \$self->{packet_buffer};
548              
549             # Receive more data if the macket header cannot be read
550 0 0         return undef if $self->{packet_read} < MACKET_HEADER_LENGTH;
551              
552             # As long as we can read a macket header
553 0           while ($self->{packet_read} > MACKET_HEADER_LENGTH) {
554             # Get the length of the next macket, plus header length.
555 0 0         if (! defined($self->{packet_goal})) {
556 0           my $pos = 0;
557             # Cached to avoid repeated decoding.
558 0           $self->{packet_goal} = Net::Wire10::Util::decode_my_uint($$packet, \$pos, 3) + MACKET_HEADER_LENGTH;
559             }
560 0 0         return undef if $self->{packet_read} < $self->{packet_goal};
561 0 0         print "Shifting a new macket totalling " . $self->{packet_goal} . " byte(s) into the macket queue.\n" if $self->{debug} & 1;
562 0           my $macket = { buf => substr($$packet, 0, $self->{packet_goal}, '') };
563 0           unshift(@{$self->{macket_queue}}, $macket);
  0            
564 0           $self->{packet_read} -= $self->{packet_goal};
565 0           $self->{packet_goal} = undef;
566             }
567             }
568              
569             # Gets the next macket in the queue
570             sub _next_macket {
571 0     0     my $self = shift;
572 0           my $macket;
573              
574             # Receive data if necessary
575 0           while (scalar(@{$self->{macket_queue}}) == 0) {
  0            
576 0           $self->_receive_packet_data;
577 0 0         print "Bytes in receive buffer: " . $self->{packet_read} . "\n" if $self->{debug} & 1;
578 0           $self->_queue_mackets;
579             }
580              
581             # Return first queued macket
582 0           $macket = pop(@{$self->{macket_queue}});
  0            
583 0           $self->_check_received_macket_type($macket);
584 0           return $macket;
585             }
586              
587             # Fail if driver is getting something completely
588             # different from what it expected
589             sub _check_received_macket_type {
590 0     0     my $self = shift;
591 0           my $macket = shift;
592 0           my $expected = $self->{expected_macket};
593 0           my $msg = "";
594 0           my $type = $self->_derive_received_macket_type($macket);
595              
596 0           $self->_dump_macket($macket);
597              
598             # If this is a error macket set error information and return,
599             # regardless of what caller expects (error mackets are always expected).
600 0 0         if ($type == MACKET_ERROR) {
601 0           return undef;
602             }
603              
604 0 0         if ($expected & MACKET_EOF) {
605 0 0         return undef if ($type == MACKET_EOF);
606 0           $msg .= "Expected EOF Macket, did not receive it!\n";
607             }
608              
609 0 0         if ($expected & MACKET_HANDSHAKE) {
610 0 0         return undef if ($type == MACKET_HANDSHAKE);
611 0           $msg .= "Expected Handshake Initialization Macket, did not recieve it!\n";
612             }
613              
614 0 0         if ($expected & MACKET_OK) {
615 0 0         return undef if ($type == MACKET_OK);
616 0           $msg .= "Expected OK Macket, did not receive it!\n";
617             }
618              
619 0 0         if ($expected & MACKET_RESULT_SET_HEADER) {
620 0 0         return undef if ($type == MACKET_RESULT_SET_HEADER);
621 0           $msg .= "Expected Result Set Header Macket, dit not receive it!\n";
622             }
623              
624 0 0         if ($expected & MACKET_COLUMN_INFO) {
625 0 0         return undef if ($type == MACKET_COLUMN_INFO);
626 0           $msg .= "Expected Column Info Macket, did not receive it!\n";
627             }
628              
629 0 0         if ($expected & MACKET_ROW_DATA) {
630 0 0         return undef if ($type == MACKET_ROW_DATA);
631 0           $msg .= "Expected Row Data Macket, did not receive it!\n";
632             }
633              
634 0 0         if ($expected & MACKET_MORE_DATA) {
635 0 0         return undef if ($type == MACKET_MORE_DATA);
636 0           $msg .= "Expected Fragmented Data Macket, did not receive it!\n";
637             }
638              
639 0           $self->_fatal_error($msg);
640             }
641              
642             # Lacking a proper indicator of message type in received mackets,
643             # try to figure out what type of macket it is based on circumstances
644             sub _derive_received_macket_type {
645 0     0     my $self = shift;
646 0           my $macket = shift;
647              
648             # If this is a error macket set error information and return
649 0 0         if (ord(substr($macket->{buf}, MACKET_HEADER_LENGTH, 1)) == 0xff) {
650 0           return $macket->{type} = MACKET_ERROR;
651             }
652              
653 0 0 0       if ((length($macket->{buf}) < MACKET_HEADER_LENGTH + 9) && (ord(substr($macket->{buf}, MACKET_HEADER_LENGTH, 1)) == 0xFE)) {
654 0           return $macket->{type} = MACKET_EOF;
655             }
656              
657 0 0 0       if ((ord(substr($macket->{buf}, MACKET_HEADER_LENGTH, 1)) == 0) && (length($macket->{buf}) > MACKET_HEADER_LENGTH + 5)) {
658 0           return $macket->{type} = MACKET_OK;
659             }
660              
661 0 0 0       if ($self->_extract_macket_number($macket) == 0 && ! defined($self->{protocol_version})) {
662 0           return $macket->{type} = MACKET_HANDSHAKE;
663             }
664              
665 0 0         if (! defined($self->{no_of_columns})) {
666 0           return $macket->{type} = MACKET_RESULT_SET_HEADER;
667             }
668              
669 0 0         if ($self->{expected_macket} & MACKET_COLUMN_INFO) {
670 0           return $macket->{type} = MACKET_COLUMN_INFO;
671             }
672              
673 0 0         if ($self->{expected_macket} & MACKET_ROW_DATA) {
674 0           return $macket->{type} = MACKET_ROW_DATA;
675             }
676              
677 0 0         if ($self->{expected_macket} & MACKET_MORE_DATA) {
678 0           return $macket->{type} = MACKET_MORE_DATA;
679             }
680              
681 0           $self->_fatal_error("Unknown macket type received");
682             }
683              
684             # Sends a message to the server
685             sub _send_mackets {
686 0     0     my $self = shift;
687 0           my $body = shift;
688 0           my $nr = shift;
689 0           my $type = shift;
690 0           my $len = length($body);
691 0           my $pos = 0;
692              
693 0           while ($len >= 0) {
694             # The server terminates the connection if the fragmented mackets
695             # (except the last, of course) are not 0xffffff bytes long.
696 0 0         my $chunk_len = $len > 0xffffff ? 0xffffff : $len;
697 0 0 0       $len = -1 if ($len == 0) or ($chunk_len < 0xffffff);
698 0           $len -= $chunk_len;
699              
700 0           my $head_len = Net::Wire10::Util::encode_my_uint($chunk_len, 3);
701 0           my $head_nr = Net::Wire10::Util::encode_my_uint($nr, 1);
702 0           my $chunk = substr($body, $pos, $chunk_len);
703 0 0         $type = MACKET_MORE_DATA if ($pos > 0);
704 0           my $macket = { buf => $head_len . $head_nr . $chunk, type => $type };
705              
706 0           $self->_dump_macket($macket);
707              
708 0           my $socket = $self->{socket};
709 0 0         die "Not connected" unless $socket;
710              
711 0           $socket->send($macket->{buf}, 0);
712 0           $nr = ($nr + 1) % 256;
713 0           $pos += $chunk_len;
714             }
715             }
716              
717             # Reads and interprets server handshake
718             sub _perform_handshake {
719 0     0     my $self = shift;
720              
721 0           $self->{expected_macket} = MACKET_HANDSHAKE;
722              
723 0           my $macket = $self->_next_macket;
724              
725             # Server will send an error instead of greeting
726             # if too many connection slots are filled.
727 0 0         if ($macket->{type} == MACKET_ERROR) {
728 0           $self->_parse_error_macket($macket, "Connect failed: ");
729 0           $self->_fatal_error;
730             }
731              
732             # Skip the macket header as it has been processed by _next_macket().
733 0           my $i = MACKET_HEADER_LENGTH;
734 0 0         printf "\n%s():\n", (caller(1))[3] if $self->{debug} & 1;
735             # Protocol version
736 0           $self->{protocol_version} = ord substr $macket->{buf}, $i, 1;
737 0 0         printf " -> Protocol Version: %d\n", $self->{protocol_version} if $self->{debug} & 1;
738              
739             # Quit if the protocol version does not match what the driver supports.
740 0 0         if ($self->{protocol_version} != 10) {
741 0           $self->_fatal_error("Only MySQL wire protocol 10 is supported at the moment\n");
742             }
743              
744 0           $i += 1;
745             # Server version
746 0           my $string_end = index($macket->{buf}, "\0", $i);
747 0 0         $self->_fatal_error("Could not decode server version.\n") if $string_end == -1;
748 0           $string_end -= $i;
749 0           $self->{server_version} = substr $macket->{buf}, $i, $string_end;
750 0 0         printf " -> Server version: %s\n", $self->{server_version} if $self->{debug} & 1;
751 0           $i += $string_end + 1;
752 0           my $left = length($macket->{buf}) - $i;
753 0 0         $self->_fatal_error("Server handshake message truncated.\n") if $left < 44;
754             # Server thread id
755 0           $self->{server_thread_id} = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$i, 4);
756 0 0         printf " -> Server thread id: %d\n", $self->{server_thread_id} if $self->{debug} & 1;
757             # Scramble buff, 1st part
758 0           $self->{salt} = substr $macket->{buf}, $i, 8;
759             # Enables the use of old passwords
760 0           $self->{salt_old} = $self->{salt};
761             # The salt part is 8 bytes long and there is a one byte filler after
762 0           $i += 8 + 1;
763             # Server_capabilities is not used at the moment
764 0           my $server_caps = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$i, 2);
765 0 0         printf " -> Server capabilities (ignored): 0x%x\n", $server_caps if $self->{debug} & 1;
766             # Server_language is not used at the moment
767 0           my $server_lang = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$i, 1);
768 0 0         printf " -> Server language (ignored): %d\n", $server_lang if $self->{debug} & 1;
769             # Server_status is not used at the moment
770 0           my $server_status = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$i, 2);
771 0 0         printf " -> Server status (ignored): 0x%x\n", $server_status if $self->{debug} & 1;
772             # 13 byte filler
773 0           $i += 13;
774             # Scramble buff, 2nd part
775             # The MySQL protocol documentation says that this part is 13 bytes long,
776             # but the last byte seems to be a filler. So we only read 12 bytes.
777 0           $self->{salt} .= substr $macket->{buf}, $i, 12;
778 0 0         printf " -> Salt: %s\n", $self->{salt} if $self->{debug} & 1;
779             # Filler
780 0           $i += 1;
781             }
782              
783             # Sends authentication, waits for answer, resends
784             # response to challenge in old format if requested by server
785             sub _perform_authentication {
786 0     0     my $self = shift;
787              
788 0           $self->_send_login_message;
789 0           $self->{expected_macket} = MACKET_EOF + MACKET_OK;
790              
791 0           my $auth_result = $self->_next_macket;
792 0 0         if ($auth_result->{type} == MACKET_EOF) {
793             # Note: this EOF packet is truncated by 4 bytes compared
794             # to normal EOF packets, parsing it is skipped.
795 0           $self->_send_old_password;
796 0           $self->{expected_macket} = MACKET_OK;
797 0           $auth_result = $self->_next_macket;
798             }
799 0 0         if ($auth_result->{type} == MACKET_OK) {
800 0           $self->_parse_ok_macket($auth_result);
801             }
802 0 0         if ($auth_result->{type} == MACKET_ERROR) {
803 0           $self->_parse_error_macket($auth_result, "Authentication failed: ");
804 0           $self->_fatal_error;
805             }
806 0 0         print "Connected to database server\n" if $self->{debug} & 1;
807             }
808              
809             # Sends new format client authentication
810             sub _send_login_message {
811 0     0     my $self = shift;
812              
813             # Obligatory flags
814 0           my $driver_flags =
815             FLAG_LONG_PASSWORD +
816             FLAG_LONG_FLAG +
817             FLAG_CONNECT_WITH_DB +
818             # Unsupported: COMPRESS
819             # Unsupported: LOCAL_FILES
820             FLAG_PROTOCOL_41 +
821             # Unsupported: SSL
822             # Unsupported: IGNORE_SIGPIPE
823             FLAG_TRANSACTIONS +
824             # Unsupported: RESERVED
825             FLAG_SECURE_CONNECTION +
826             # Unsupported: MULTI_STATEMENTS
827             # Necessary to avoid server abort: FLAG_MULTI_RESULTS
828             FLAG_MULTI_RESULTS;
829             # Unsupported: SSL_VERIFY_SERVER_CERT
830             # Unsupported: REMEMBER_OPTIONS
831              
832             # Optional flags
833 0           my $customizable_flags =
834             FLAG_FOUND_ROWS +
835             FLAG_NO_SCHEMA +
836             FLAG_ODBC +
837             FLAG_IGNORE_SPACE +
838             FLAG_INTERACTIVE;
839              
840 0           my $flags = $driver_flags | ($customizable_flags & $self->{flags});
841 0           my $body .= Net::Wire10::Util::encode_my_uint($flags, 4);
842             # Max macket size. Completely disregarded by the server,
843             # which just overflows macket data onto other mackets when
844             # sending and accepts overflowed data when receiving.
845             # See also note in _send_mackets().
846 0           $body .= Net::Wire10::Util::encode_my_uint(0x01000000, 4);
847             # Character set; hardcoded to UTF-8, used in _parse_column_info_macket().
848 0           $body .= chr(UTF8_GENERAL_CI);
849             # 23 bytes filler.
850 0           $body .= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
851             # Null-terminated: user name
852 0           $body .= $self->{user} . "\0";
853 0 0         if (length($self->{password}) > 0) {
854 0           $body .= "\x14" . Net::Wire10::Password->scramble($self->{password}, $self->{salt});
855             } else {
856 0           $body .= "\0";
857             }
858 0 0         if (defined($self->{database})) {
859             # Documentation says there should be a filler here,
860             # but other clients don't send that.
861             #$body .= "\0";
862             # Null-terminated: initial default database name.
863 0           $body .= $self->{database};
864 0           $body .= "\0";
865             }
866 0           $self->_send_mackets($body, 1, MACKET_AUTHENTICATE);
867             }
868              
869             # Sends old format client authentication
870             sub _send_old_password {
871 0     0     my $self = shift;
872 0           my $body = Net::Wire10::Password32->scramble(
873             $self->{password}, $self->{salt_old}, 1
874             ) . "\0";
875 0           $self->_send_mackets($body, 3, MACKET_AUTHENTICATE);
876             }
877              
878             # Execute a SQL command
879             sub _execute_query {
880 0     0     my $self = shift;
881 0           my $sql = shift;
882 0           my $wantstream = shift;
883              
884 0           $self->_check_streaming;
885 0           $self->_check_connected;
886 0           $self->_reset_command_state;
887 0           $self->_reset_timeout($self->{query_timeout});
888 0 0         $self->{streaming} = 1 if $wantstream;
889              
890 0           my $iterator = Net::Wire10::Results->new($self);
891 0 0         $self->{streaming_iterator} = $iterator if $wantstream;
892              
893             # The protocol is configured to always use UTF-8 during handskake, to
894             # avoid messing with all the local character sets. Therefore any input
895             # string needs to be automatically converted if it is not already UTF-8.
896 0 0 0       utf8::upgrade($sql) if defined($sql) and not utf8::is_utf8($sql);
897              
898 0 0         printf "Executing query: %s%s\n", substr($sql, 0, 100), length($sql) >= 100 ? " ..." : "" if $self->{debug} & 1;
    0          
899              
900 0           $self->_execute_command(COMMAND_QUERY, $sql, $iterator);
901 0           return $iterator;
902             }
903              
904             # Send a protocol command message
905             sub _execute_command {
906 0     0     my $self = shift;
907 0           my $command = shift;
908 0           my $param = shift;
909 0           my $iterator = shift;
910              
911             # Abort early if the driver is no longer connected.
912 0           $self->_check_connected;
913              
914             # Strip the utf8 flag from the string,
915             # otherwise the socket send() complains.
916 0           Encode::_utf8_off($param);
917              
918             # Send the SQL command
919 0           my $body = $command . $param;
920 0           $self->_send_mackets($body, 0, MACKET_COMMAND);
921 0           $self->{expected_macket} = MACKET_OK | MACKET_RESULT_SET_HEADER;
922              
923             # Receive the result from the database
924 0           my $macket = $self->_next_macket;
925              
926 0 0         if ($macket->{type} == MACKET_ERROR) {
927 0           $self->_detach_results($iterator);
928 0           $self->_parse_error_macket($macket);
929 0           $self->_vanilla_error;
930             }
931 0 0         if ($macket->{type} == MACKET_RESULT_SET_HEADER) {
932 0           my $pos = MACKET_HEADER_LENGTH;
933 0           $self->_parse_result_set_header_macket($macket, \$pos);
934 0           $self->_retrieve_column_info($iterator);
935 0 0         $self->_retrieve_results($iterator) unless $self->{streaming};
936             }
937 0 0         if ($macket->{type} == MACKET_OK) {
938 0           $self->_parse_ok_macket($macket, $iterator);
939 0           $self->_detach_results($iterator);
940             }
941             }
942              
943             # Reads and interprets result set header
944             sub _parse_result_set_header_macket {
945 0     0     my $self = shift;
946 0           my $macket = shift;
947 0           my $pos = shift;
948              
949 0           $self->{no_of_columns} = $self->_decode_lcb_or_fail($macket->{buf}, $pos);
950 0 0         printf "Number of columns: %d\n", $self->{no_of_columns} if $self->{debug} & 1;
951             # Optionally the "extra" field is in the macket
952 0           my $macket_length = length($macket->{buf}) - MACKET_HEADER_LENGTH;
953 0 0         if ($macket_length - 1 > $pos) {
954 0           my $extra = $self->_decode_lcb_or_fail($macket->{buf}, $pos);
955 0 0         printf "Extra information (ignored): %d\n", $extra if $self->{debug} & 1;
956             }
957             }
958              
959             # Reads and stores error message, sql state and error code
960             sub _parse_error_macket {
961 0     0     my $self = shift;
962 0           my $macket = shift;
963 0   0       my $extra = shift || '';
964              
965 0 0         if ($macket->{type} != MACKET_ERROR) {
966 0           $self->_fatal_error("Expected error macket");
967             }
968              
969             # skip macket header
970 0           my $pos = MACKET_HEADER_LENGTH;
971             # skip macket type
972 0           $pos += 1;
973 0           my $left = length($macket->{buf}) - $pos;
974 0 0         $self->_fatal_error("Truncated error macket") if $left < 2;
975             # error code
976 0           my $code = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 2);
977             # Documentation says there always is a SQLSTATE marker here,
978             # but that is not true.
979 0           my $sqlstate_marker = substr($macket->{buf}, $pos, 1);
980 0           my $sqlstate = '';
981 0 0         if ($sqlstate_marker eq '#') {
982             # skip SQL state marker
983 0           $pos += 1;
984             # read SQL state
985 0           my $sqlstate = substr($macket->{buf}, $pos, 5);
986 0           $pos += 5;
987             }
988             # message
989 0           my $message = substr($macket->{buf}, $pos);
990 0           Encode::_utf8_on($message);
991              
992             # create error info object
993 0           $self->{error} = Net::Wire10::Error->new($code, $sqlstate, $extra . $message);
994             }
995              
996             # Reads column info and EOF, possibly
997             # interrupted at any point by an error from the server
998             sub _retrieve_column_info {
999 0     0     my $self = shift;
1000 0           my @queue = ();
1001 0           my $macket;
1002 0           my $iterator = shift;
1003              
1004 0           $self->{expected_macket} = MACKET_COLUMN_INFO | MACKET_EOF;
1005             # Put all field mackets in the selected queue
1006 0           do {
1007 0           $macket = $self->_next_macket;
1008 0 0         if ($macket->{type} == MACKET_ERROR) {
1009 0           $self->_parse_error_macket($macket, "Server reported error while reading column info: ");
1010 0           $self->_fatal_error;
1011             }
1012 0 0         if ($macket->{type} == MACKET_COLUMN_INFO) {
1013 0           my $column_info = $self->_parse_column_info_macket($macket);
1014 0           push(@queue, $column_info);
1015             }
1016             } until ($macket->{type} == MACKET_EOF);
1017 0 0         if ($self->{no_of_columns} ne scalar @queue) {
1018 0           $self->_fatal_error(sprintf(
1019             "Server reported %d columns, but sent %d",
1020             $self->{no_of_columns},
1021             scalar @queue
1022             ));
1023             }
1024 0           $iterator->{column_info} = \@queue;
1025 0           $self->_parse_eof_macket($macket, $iterator);
1026             }
1027              
1028             # Reads all rows in result set
1029             sub _retrieve_results {
1030 0     0     my $self = shift;
1031 0           my $iterator = shift;
1032              
1033             # Put all row data in the selected queue
1034 0           while ($self->_retrieve_row_data($iterator)) {}
1035             }
1036              
1037             # Reads row data or EOF, possibly
1038             # interrupted at any point by an error from the server
1039             sub _retrieve_row_data {
1040 0     0     my $self = shift;
1041 0           my $iterator = shift;
1042              
1043 0           $self->{expected_macket} = MACKET_ROW_DATA + MACKET_EOF;
1044 0           my $macket = $self->_next_macket;
1045              
1046 0 0         if ($macket->{type} == MACKET_ERROR) {
1047 0           $self->_parse_error_macket($macket, "Server reported error while reading row data: ");
1048 0           $self->_fatal_error;
1049             }
1050 0 0         if ($macket->{type} == MACKET_ROW_DATA) {
1051             # Note: The manual does not specify how the server fragments data.
1052             # One possibility would be that if the server sends data that fits
1053             # exactly on a macket boundary, then sends an additional completely
1054             # empty macket, to allow the client to assume that a maxed out macket
1055             # means that more fragments will follow. Another possibility would
1056             # be that the server expects the client to deduce whether more mackets
1057             # are coming based on the contents of each macket, since fragmented
1058             # mackets only occur for data mackets which have an additional length
1059             # indicator (for the field data) inside the macket. For the usual
1060             # lack of documentation, the method used below is a guess.
1061 0           my $nasty = length($macket->{buf});
1062 0           while ($nasty == MACKET_HEADER_LENGTH + 0xffffff) {
1063             # Glue together to form proper macket
1064             # (with invalid macket_length).
1065 0 0         printf "Fragmented macket found, retrieving one more fragment macket.\n" if $self->{debug} & 1;
1066 0           $self->{expected_macket} = MACKET_MORE_DATA;
1067 0           my $next_macket = $self->_next_macket;
1068 0 0         if ($macket->{type} == MACKET_ERROR) {
1069 0           $self->_parse_error_macket($macket, "Server reported error while reading more row data: ");
1070 0           $self->_fatal_error;
1071             }
1072 0           $nasty = length($next_macket->{buf});
1073             # Remove header from next fragment.
1074 0           substr($next_macket->{buf}, 0, MACKET_HEADER_LENGTH, "");
1075             # Concatenate macket contents.
1076 0           $macket->{buf} .= $next_macket->{buf};
1077             }
1078             # Remove header from first fragment.
1079 0           substr($macket->{buf}, 0, MACKET_HEADER_LENGTH, "");
1080 0 0         printf "Unshifting %d byte(s) of row data onto queue.\n", length($macket->{buf}) if $self->{debug} & 1;
1081 0           push(@{$iterator->{row_data}}, $macket->{buf});
  0            
1082             # More data may be available.
1083 0           return 1;
1084             }
1085 0 0         if ($macket->{type} == MACKET_EOF) {
1086             # Read EOF macket
1087 0           $self->_parse_eof_macket($macket, $iterator);
1088 0           $self->_detach_results($iterator);
1089             # No more data available.
1090 0           return 0;
1091             }
1092             }
1093              
1094             # Disconnect result set from driver, must only be done after all results have been read
1095             sub _detach_results {
1096 0     0     my $self = shift;
1097 0           my $iterator = shift;
1098 0           $iterator->{wire}->{streaming_iterator} = undef;
1099 0           $iterator->{wire}->{streaming} = 0;
1100 0           $iterator->{wire} = undef;
1101             }
1102              
1103             # Reads and interprets OK, saving the number of affected rows,
1104             # the insert id, and the server message. Returns the number of
1105             # affected rows
1106             sub _parse_ok_macket {
1107 0     0     my $self = shift;
1108 0           my $macket = shift;
1109 0           my $iterator = shift;
1110              
1111             # Because affected rows is a Length Coded Binary
1112             # we use pointers to the position in the macket.
1113             # The position is updated in each method called
1114             # to ensure that the macket is read correctly.
1115             # First, skip macket header and macket type.
1116 0           my $pos = MACKET_HEADER_LENGTH + 1;
1117 0 0         printf "\n%s():\n", (caller(1))[3] if $self->{debug} & 1;
1118             # Affected rows
1119 0           my $affected = $self->_decode_lcb_or_fail($macket->{buf}, \$pos);
1120 0 0         printf " -> Affected rows: %d\n", $affected if $self->{debug} & 1;
1121             # Insert id
1122 0           my $raw_id = $self->_skip_lcb_or_fail($macket->{buf}, \$pos);
1123 0 0         printf " -> Insert id (decode postponed): %d byte(s)\n", length($raw_id) if $self->{debug} & 1;
1124 0           my $left = length($macket->{buf}) - $pos;
1125 0 0         $self->_fatal_error("Truncated OK macket") if $left < 4;
1126             # Server status
1127 0           my $status = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 2);
1128 0 0         printf " -> Server status flags (ignored): 0x%x\n", $status if $self->{debug} & 1;
1129             # Warning count
1130 0           my $warnings = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 2);
1131 0 0         printf " -> Warning count: %d\n", $warnings if $self->{debug} & 1;
1132             # Message
1133 0           my $message = substr($macket->{buf}, $pos);
1134 0           Encode::_utf8_on($message);
1135 0 0         printf " -> Server message (ignored): %s\n", $message if $self->{debug} & 1;
1136              
1137 0 0         if (defined($iterator)) {
1138 0           $iterator->{no_of_affected_rows} = $affected;
1139 0           $iterator->{raw_insert_id} = $raw_id;
1140 0           $iterator->{warnings} = $warnings;
1141             }
1142             }
1143              
1144             # Reads and interprets EOF, saving relevant values.
1145             sub _parse_eof_macket {
1146 0     0     my $self = shift;
1147 0           my $macket = shift;
1148 0           my $iterator = shift;
1149              
1150 0           my $pos = MACKET_HEADER_LENGTH + 1;
1151 0           my $left = length($macket->{buf}) - $pos;
1152 0 0         $self->_fatal_error("Truncated EOF macket") if $left < 4;
1153 0 0         printf "\n%s():\n", (caller(1))[3] if $self->{debug} & 1;
1154             # Warning count
1155 0           my $warnings = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 2);
1156 0 0         printf " -> Warning count: %d\n", $warnings if $self->{debug} & 1;
1157             # Server status
1158 0           my $status = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 2);
1159 0 0         printf " -> Server status flags: 0x%x\n", $status if $self->{debug} & 1;
1160 0 0         $self->_fatal_error("Query yielded multiple results (not supported)") if $status & STATUS_MORE_RESULTS_EXISTS;
1161 0 0         $iterator->{warnings} = $warnings if defined($iterator);
1162             }
1163              
1164             # Reads and interprets column information
1165             sub _parse_column_info_macket {
1166             # Metadata always in UTF-8; see collation in _send_login_message().
1167 0     0     my $self = shift;
1168 0           my $macket = shift;
1169              
1170             # Skip the header.
1171 0           my $pos = MACKET_HEADER_LENGTH;
1172             # Catalog
1173 0           my $catalog = $self->_decode_string_or_fail($macket->{buf}, \$pos);
1174 0           Encode::_utf8_on($catalog);
1175             # DB
1176 0           my $db = $self->_decode_string_or_fail($macket->{buf}, \$pos);
1177 0           Encode::_utf8_on($db);
1178             # Table
1179 0           my $table = $self->_decode_string_or_fail($macket->{buf}, \$pos);
1180 0           Encode::_utf8_on($table);
1181             # Org_table
1182 0           my $orig_table = $self->_decode_string_or_fail($macket->{buf}, \$pos);
1183 0           Encode::_utf8_on($orig_table);
1184             # Name
1185 0           my $column = $self->_decode_string_or_fail($macket->{buf}, \$pos);
1186 0           Encode::_utf8_on($column);
1187             # Org_name
1188 0           my $orig_column = $self->_decode_string_or_fail($macket->{buf}, \$pos);
1189 0           Encode::_utf8_on($orig_column);
1190             # Filler
1191 0           $pos += 1;
1192 0           my $left = length($macket->{buf}) - $pos;
1193 0 0         $self->_fatal_error("Truncated column info macket") if $left < 10;
1194             # Charset number
1195 0           my $collation = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 2);
1196             # Skip reading display length, because some server functions, eg. ASBINARY(),
1197             # sets this to 0xFFFFFFFF unsigned, which is too big for 32-bit Perl.
1198 0           $pos += 4;
1199             #my $display_length = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 4);
1200             # Column data type
1201 0           my $data_type = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 1);
1202             # Flags
1203 0           my $flags = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 2);
1204 0           my $sane_flags = $flags & USEFUL_COLUMN_FLAGS;
1205             # Decimal scale (for DECIMAL or NUMERIC data types)
1206 0           my $decimal_scale = Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 1);
1207             # Filler
1208 0           $pos += 2;
1209 0 0         printf "\n%s():\n", (caller(1))[3] if $self->{debug} & 1;
1210             # Optionally the default field is available in the macket
1211 0           my $macket_length = length($macket->{buf}) - MACKET_HEADER_LENGTH;
1212 0 0         if ($macket_length - 1 > $pos) {
1213 0           $self->{extra} = $self->_decode_lcb_or_fail($macket->{buf}, \$pos);
1214 0 0         print " -> Default (ignored): " . $self->{extra} if $self->{debug} & 1;
1215             }
1216 0           my $format =
1217             " -> Catalog (ignored): %s\n -> Name: %s\n -> Object: %s\n".
1218             " -> Source Column: %s\n -> Source Table: %s\n -> Source Database: %s\n".
1219             " -> Collation: %s\n -> Data Type: %s\n -> Decimal Scale: %s\n".
1220             " -> Display (ignored): Undeciphered\n -> Flags: 0x%x\n";
1221 0 0         printf $format,
1222             $catalog, $column, $table,
1223             $orig_column, $orig_table, $db,
1224             $collation, $data_type, $decimal_scale,
1225             $flags
1226             if $self->{debug} & 1;
1227             return {
1228 0           name => $column,
1229             object => $table,
1230             orig_database => $db,
1231             orig_table => $orig_table,
1232             orig_column => $orig_column,
1233             collation => $collation,
1234             data_type => $data_type,
1235             decimal_scale => $decimal_scale,
1236             flags => $sane_flags
1237             };
1238             }
1239              
1240             # Verify the integrity of a row data macket by checking for each
1241             # field value that it is contained within the macket's total length
1242             sub _field_value_exceeds_buffer {
1243 0     0     my $self = shift;
1244 0           my $buf = shift;
1245 0           my $pos = shift;
1246 0           my $len = length($buf);
1247 0           while ($pos < $len) {
1248 0           Net::Wire10::Util::skip_string($buf, \$pos);
1249             }
1250 0           return $pos - $len;
1251             }
1252              
1253             # Given a macket, extract serial number from its header
1254             sub _extract_macket_number {
1255 0     0     my $self = shift;
1256 0           my $macket = shift;
1257              
1258 0           return ord(substr($macket->{buf}, 3, 1));
1259             }
1260              
1261             # Given a macket, extract length from its header
1262             sub _extract_macket_length {
1263 0     0     my $self = shift;
1264 0           my $macket = shift;
1265 0           my $pos = 0;
1266              
1267 0           return Net::Wire10::Util::decode_my_uint($macket->{buf}, \$pos, 3);
1268             }
1269              
1270             # Wrap the skip_lcb library function in an error handler,
1271             # catching errors and sending them to the driver's _fatal_error()
1272             sub _skip_lcb_or_fail {
1273 0     0     my $self = shift;
1274 0           my $buf = shift;
1275 0           my $pos = shift;
1276              
1277 0           my $result = eval {
1278 0           return Net::Wire10::Util::skip_lcb($buf, $pos);
1279             };
1280 0 0         $self->_fatal_error($@) if $@;
1281 0           return $result;
1282             }
1283              
1284             # Wrap the decode_lcb library function in an error handler,
1285             # catching errors and sending them to the driver's _fatal_error()
1286             sub _decode_lcb_or_fail {
1287 0     0     my $self = shift;
1288 0           my $buf = shift;
1289 0           my $pos = shift;
1290              
1291 0           my $result = eval {
1292 0           return Net::Wire10::Util::decode_lcb($buf, $pos);
1293             };
1294 0 0         $self->_fatal_error($@) if $@;
1295 0           return $result;
1296             }
1297              
1298             # Wrap the decode_string library function in an error handler,
1299             # catching errors and sending them to the driver's _fatal_error()
1300             sub _decode_string_or_fail {
1301 0     0     my $self = shift;
1302 0           my $buf = shift;
1303 0           my $pos = shift;
1304              
1305 0           my $result = eval {
1306 0           return Net::Wire10::Util::decode_string($buf, $pos);
1307             };
1308 0 0         $self->_fatal_error($@) if $@;
1309 0           return $result;
1310             }
1311              
1312             # Resets the command execution status
1313             sub _reset_command_state {
1314 0     0     my $self = shift;
1315             # Disconnect streaming iterator.
1316 0 0         $self->_detach_results($self->{streaming_iterator}) if defined($self->{streaming_iterator});
1317             # Reset internal column counter.
1318 0           $self->{no_of_columns} = undef;
1319             # Reset error state.
1320 0           $self->{error} = undef;
1321             # Reset cancel flag.
1322 0           $self->{cancelling} = 0;
1323             }
1324              
1325             # Reset entire connection
1326             sub _reset_connection_state {
1327 0     0     my $self = shift;
1328 0           $self->{protocol_version} = undef;
1329 0           $self->{server_version} = undef;
1330 0           $self->{salt} = '';
1331 0           $self->{packet_buffer} = '';
1332 0           $self->{packet_goal} = undef;
1333 0           $self->{packet_read} = 0;
1334 0           $self->{socket} = undef;
1335 0           $self->{io_select} = undef;
1336 0           $self->{expected_macket} = undef;
1337 0           $self->{macket_queue} = [];
1338 0           $self->{command_expire_time} = undef;
1339             }
1340              
1341             # Dumps the packet to standard output, useful for debugging
1342             sub _dump_packet {
1343 0     0     my $self = shift;
1344 0 0         return unless $self->{debug} & 4;
1345 0           my $packet = shift;
1346 0           my $str = sprintf "\n%s():\n", (caller(1))[3];
1347 0           my $len = length($packet);
1348 0           my $skipped = 0;
1349 0           my $pos = -16;
1350 0           while ($packet =~ /(.{1,16})/sg) {
1351 0           $pos += 16;
1352 0 0         unless ($self->{debug} & 8) {
1353 0 0 0       if (($len > 528) && ($pos > 256) && ($len - $pos > 256)) {
      0        
1354 0 0         if (! $skipped) {
1355 0           print "\n\n" . ' ' x 25 . "... snip more data ...\n";
1356 0           $skipped = 1;
1357             }
1358 0           next;
1359             }
1360             }
1361 0           my $line = $1;
1362 0           $str .= join ' ', map {sprintf '%02X', ord $_} split //, $line;
  0            
1363 0           $str .= ' ' x (16 - length $line);
1364 0           $str .= ' ';
1365 0 0         $str .= join '', map {
1366 0           sprintf '%s', (/[\w\d\*\,\?\%\=\'\;\(\)\.-]/) ? $_ : '.'
1367             } split //, $line;
1368 0           print $str;
1369 0           $str = "\n";
1370             }
1371 0           print $str;
1372             }
1373              
1374             # Dumps the macket to standard output, useful for debugging.
1375             sub _dump_macket {
1376 0     0     my $self = shift;
1377 0 0         return unless $self->{debug} & 2;
1378 0           my $macket = shift;
1379 0           my $str = sprintf "\n%s():\n", (caller(1))[3];
1380 0           $str .= sprintf " -> serial: %d\n", Net::Wire10::_extract_macket_number($self, $macket);
1381 0           $str .= sprintf " -> length: %d\n", Net::Wire10::_extract_macket_length($self, $macket);
1382 0           my $type = $macket->{type};
1383 0           $str .= sprintf " -> type: %s\n", $Net::Wire10::MACKET_NAMES{$type};
1384 0           $str .= sprintf " -> data: ";
1385 0           my $len = length($macket->{buf});
1386 0           my $skipped = 0;
1387 0           my $pos = -16;
1388 0           while ($macket->{buf} =~ /(.{1,16})/sg) {
1389 0           $pos += 16;
1390 0 0         unless ($self->{debug} & 16) {
1391 0 0 0       if (($len > 528) && ($pos > 256) && ($len - $pos > 256)) {
      0        
1392 0 0         if (! $skipped) {
1393 0           print "\n\n" . ' ' x 25 . "... snip more data ...\n";
1394 0           $skipped = 1;
1395             }
1396 0           next;
1397             }
1398             }
1399 0           my $line = $1;
1400 0 0         $str .= ' ' x 13 if substr($str, -1, 1) eq "\n";
1401 0           $str .= join ' ', map {sprintf '%02X', ord $_} split //, $line;
  0            
1402 0           $str .= ' ' x (16 - length $line);
1403 0           $str .= ' ';
1404 0 0         $str .= join '', map {
1405 0           sprintf '%s', (/[\w\d\*\,\?\%\=\'\;\(\)\.-]/) ? $_ : '.'
1406             } split //, $line;
1407 0           print $str;
1408 0           $str = "\n";
1409             }
1410 0           print $str;
1411             }
1412              
1413              
1414              
1415             package Net::Wire10::Results;
1416              
1417 1     1   15 use strict;
  1         2  
  1         58  
1418 1     1   6 use warnings;
  1         3  
  1         45  
1419 1     1   6 use Encode;
  1         1  
  1         1924  
1420              
1421             # Constructor
1422             sub new {
1423 0     0     my $class = shift;
1424 0           my $wire = shift;
1425 0           return bless {
1426             wire => $wire,
1427             column_info => [],
1428             row_data => []
1429             }, $class;
1430             }
1431              
1432             # Gets next row as an array
1433             sub next_array {
1434 0     0     my $self = shift;
1435 0           my @result;
1436             my $row;
1437 0           my $wire = $self->{wire};
1438              
1439             # Note: A die() from this context often brings an application down.
1440             # For disconnected result sets, row data could be integrity
1441             # checked during query() to simplify error handling for
1442             # applications.
1443              
1444 0 0         if (defined($wire)) {
1445             # In streaming mode, fetch a row
1446 0 0         return undef unless $wire->_retrieve_row_data($self);
1447             }
1448              
1449             # Return unless there is another row available
1450 0 0         return undef if scalar(@{$self->{row_data}}) == 0;
  0            
1451              
1452 0           $row = shift(@{$self->{row_data}});
  0            
1453 0           my $pos = 0;
1454 0           for (my $i = 1; $i <= scalar(@{$self->{column_info}}); $i++) {
  0            
1455 0           my $fieldvalue = eval {
1456 0           return Net::Wire10::Util::decode_string($row, \$pos);
1457             };
1458 0 0         $self->_abort($@) if $@;
1459 0           my $collation = $self->{column_info}->[$i - 1]->{"collation"};
1460 0 0         $Net::Wire10::UTF8_COLLATIONS{$collation} and Encode::_utf8_on($fieldvalue);
1461 0           push @result, $fieldvalue;
1462             }
1463              
1464 0           return \@result;
1465             }
1466              
1467             # Leave driver in a consistent state and then die.
1468             sub _abort {
1469 0     0     my $self = shift;
1470 0           my $msg = shift;
1471 0           eval {
1472 0           $self->spool;
1473             };
1474 0           die $msg;
1475             }
1476              
1477             # Gets next row as a hash
1478             sub next_hash {
1479 0     0     my $self = shift;
1480 0           my $row = $self->next_array;
1481 0 0         return undef unless defined $row;
1482 0           my %result = map { $_->{name} => shift(@{$row}) } @{$self->{column_info}};
  0            
  0            
  0            
1483 0           return \%result;
1484             }
1485              
1486             # Retrieve and store remaining rows
1487             sub spool {
1488 0     0     my $self = shift;
1489 0           my $wire = $self->{wire};
1490 0 0         return undef unless defined($wire);
1491 0           $wire->_retrieve_results($self);
1492 0           return undef;
1493             }
1494              
1495             # Retrieve and dispose of remaining rows
1496             sub flush {
1497 0     0     my $self = shift;
1498 0           while ($self->next_array) {};
1499 0           return undef;
1500             }
1501              
1502             # Get names or other information on every column
1503             sub get_column_info {
1504 0     0     my $self = shift;
1505 0           my $what = shift;
1506 0           my @info = @{$self->{column_info}};
  0            
1507 0 0         return @info unless defined($what);
1508 0           return map { $_->{$what} } @info;
  0            
1509             }
1510              
1511             # Did the query return a set of results or not
1512             sub has_results {
1513 0     0     my $self = shift;
1514 0 0         return scalar(@{$self->{column_info}}) ? 1 : 0;
  0            
1515             }
1516              
1517             # Get the number of affected rows
1518             sub get_no_of_affected_rows {
1519 0     0     my $self = shift;
1520 0           return $self->{no_of_affected_rows};
1521             }
1522              
1523             # Get the number of selected rows
1524             sub get_no_of_selected_rows {
1525 0     0     my $self = shift;
1526 0 0         return 0 unless defined $self->{row_data};
1527 0           return scalar(@{$self->{row_data}});
  0            
1528             }
1529              
1530             # Get the insert id
1531             sub get_insert_id {
1532 0     0     my $self = shift;
1533 0           my $pos = 0;
1534 0           my $insert_id = eval {
1535 0           return Net::Wire10::Util::decode_my_uint($self->{raw_insert_id}, \$pos, length($self->{raw_insert_id}));
1536             };
1537 0 0         $self->_abort($@) if $@;
1538 0           return $insert_id;
1539             }
1540              
1541             # Get the number of warnings
1542             sub get_warning_count {
1543 0     0     my $self = shift;
1544 0           return $self->{warnings};
1545             }
1546              
1547              
1548              
1549             package Net::Wire10::PreparedStatement;
1550              
1551 1     1   9 use strict;
  1         1  
  1         40  
1552 1     1   4 use warnings;
  1         3  
  1         195  
1553 1     1   6 use utf8;
  1         3  
  1         10  
1554 1     1   30 use Encode;
  1         2  
  1         1190  
1555              
1556             # Constructor
1557             sub new {
1558 0     0     my $class = shift;
1559 0           my $wire = shift;
1560 0           my $sql = shift;
1561              
1562             # Input is either iso8859-1 or Unicode, handle as Unicode internally.
1563 0 0 0       utf8::upgrade($sql) if defined($sql) and not utf8::is_utf8($sql);
1564              
1565             # Find all "?" placeholders in query.
1566 0           my @tokens = Net::Wire10::Util::tokenize($sql);
1567              
1568 0           return bless {
1569             wire => $wire,
1570             tokens => \@tokens,
1571             params => [],
1572             }, $class;
1573             }
1574              
1575             # Set a parameter at a given index to a given value.
1576             sub set_parameter {
1577 0     0     my $self = shift;
1578 0           my $index = shift;
1579 0           my $value = shift;
1580 0   0       my $datatype = shift || Net::Wire10::DATA_TEXT;
1581              
1582             # If input is iso8859-1 or Unicode, handle as Unicode.
1583 0 0 0       utf8::upgrade($value) if defined $value and not (($datatype == Net::Wire10::DATA_BINARY) or utf8::is_utf8($value));
      0        
1584              
1585             # Store for later. Placeholders are numbered beginning with 1.
1586 0           @{$self->{params}}[$index - 1] = $value;
  0            
1587              
1588 0           return undef;
1589             }
1590              
1591             # Clear a parameter at a given index, or all parameters if no index given.
1592             sub clear_parameter {
1593 0     0     my $self = shift;
1594 0           my @indices = @_;
1595              
1596 0 0         @{$self->{params}} = [] unless scalar @indices > 0;
  0            
1597 0           foreach my $index (@indices) {
1598 0           @{$self->{params}}[$index - 1] = undef;
  0            
1599             }
1600              
1601 0           return undef;
1602             }
1603              
1604             # Return the number of ? tokens in the prepared statement.
1605             sub get_marker_count {
1606 0     0     my $self = shift;
1607 0           return scalar grep(/^\?$/, @{$self->{tokens}});
  0            
1608             }
1609              
1610             # See note about split and whitespace in Net::Wire10::Util.
1611             my $whitespace = qr/^[\ \r\n\013\t\f]$/;
1612              
1613             # Probably degrades performance quite a bit, necessary due to server bug:
1614             # http://bugs.mysql.com/bug.php?id=1337
1615             my $workaround_bug_1337 = qr/^[0-9]+$/;
1616              
1617             # Assemble and execute prepared statement.
1618             sub _execute {
1619 0     0     my $self = shift;
1620 0           my $wantstream = shift;
1621 0           my $wire = $self->{wire};
1622              
1623             # Replace tokens with parameters.
1624 0           my $prepared = '';
1625 0           my $i = 0;
1626 0           my $has_charset = 0;
1627 0           foreach my $token (@{$self->{tokens}}) {
  0            
1628             # Look for a ? token.
1629 0 0         if ($token ne '?') {
1630 0           $prepared .= $token;
1631             # Look for character set associations for upcoming ? tokens.
1632 0           my $first = substr($token, 0, 1);
1633 0 0         $has_charset = 0 if $first !~ $whitespace;
1634 0 0         $has_charset = 1 if $first eq '_';
1635             # Fast-forward to next token.
1636 0           next;
1637             }
1638              
1639             # Fetch and quote parameter, or add NULL for undef.
1640 0           my $value = $self->{params}->[$i++];
1641 0 0         unless (defined($value)) {
1642 0           $prepared .= 'NULL';
1643 0           next;
1644             }
1645 0 0         $value = Net::Wire10::Util::quote($value) if $value !~ $workaround_bug_1337;
1646              
1647             # If input is binary, tell the database server that it's binary.
1648             # It usually doesn't matter much because binary data is usually
1649             # used in a binary context anyway, but it fixes various uncommon
1650             # scenarios such as doing a CONVERT on a binary string.
1651 0 0 0       $prepared .= '_binary' unless utf8::is_utf8($value) or $has_charset;
1652              
1653             # If input is binary, make sure that Perl doesn't try to translate it
1654             # from iso8859-1 (which it isn't) to Unicode when the string is joined
1655             # with actual Unicode text to form a MySQL query, which is a character
1656             # array of mixed text and binary data.
1657 0 0         Encode::_utf8_on($value) unless utf8::is_utf8($value);
1658              
1659             # Add parameter in place of token.
1660 0           $prepared .= $value;
1661             }
1662              
1663 0 0         print "Assembled statement: " . $prepared . "\n" if $wire->{debug} & 1;
1664 0 0         return $wire->stream($prepared) if $wantstream;
1665 0           return $wire->query($prepared);
1666             }
1667              
1668             # Run the prepared statement and spool results.
1669             sub query {
1670 0     0     my $self = shift;
1671 0           return $self->_execute(0);
1672             }
1673              
1674             # Run the prepared statement and return a result object for streaming.
1675             sub stream {
1676 0     0     my $self = shift;
1677 0           return $self->_execute(1);
1678             }
1679              
1680              
1681              
1682             package Net::Wire10::Error;
1683              
1684 1     1   7 use strict;
  1         3  
  1         44  
1685 1     1   5 use warnings;
  1         2  
  1         212  
1686              
1687             # Constructor
1688             sub new {
1689 0     0     my $class = shift;
1690 0           my $code = shift;
1691 0           my $state = shift;
1692 0           my $msg = shift;
1693              
1694 0           return bless {
1695             code => $code,
1696             state => $state,
1697             message => $msg,
1698             }, $class;
1699             }
1700              
1701             # Get the error code
1702             sub get_error_code {
1703 0     0     my $self = shift;
1704 0           return $self->{code};
1705             }
1706              
1707             # Get the error SQL state designation
1708             sub get_error_state {
1709 0     0     my $self = shift;
1710 0 0         return $self->{state} ? $self->{state} : '';
1711             }
1712              
1713             # Get the error message
1714             sub get_error_message {
1715 0     0     my $self = shift;
1716 0           return $self->{message};
1717             }
1718              
1719              
1720              
1721             package Net::Wire10::Util;
1722              
1723 1     1   31 use strict;
  1         2  
  1         29  
1724 1     1   5 use warnings;
  1         2  
  1         41  
1725              
1726 1     1   4 use constant LCB_NULL => 251;
  1         2  
  1         70  
1727 1     1   4 use constant LCB_UINT16 => 252;
  1         7  
  1         40  
1728 1     1   5 use constant LCB_UINT24 => 253;
  1         2  
  1         50  
1729 1     1   4 use constant LCB_UINT64 => 254;
  1         2  
  1         38  
1730 1     1   12 use constant UINT8_LENGTH => 1;
  1         1  
  1         52  
1731 1     1   5 use constant UINT16_LENGTH => 2;
  1         2  
  1         43  
1732 1     1   5 use constant UINT24_LENGTH => 3;
  1         1  
  1         49  
1733 1     1   5 use constant UINT32_LENGTH => 4;
  1         15  
  1         56  
1734 1     1   5 use constant UINT64_LENGTH => 8;
  1         3  
  1         2059  
1735             my @LCB_LENGTHS = ();
1736             $LCB_LENGTHS[LCB_NULL] = 0;
1737             $LCB_LENGTHS[LCB_UINT16] = UINT16_LENGTH;
1738             $LCB_LENGTHS[LCB_UINT24] = UINT24_LENGTH;
1739             $LCB_LENGTHS[LCB_UINT64] = UINT64_LENGTH;
1740              
1741             # Encode a given uint into wire protocol format, return as string of given length.
1742             sub encode_my_uint {
1743 0     0     my $uint = shift;
1744 0           my $wirelen = shift;
1745              
1746 0           return substr(pack('V', $uint), 0, $wirelen);
1747             }
1748              
1749             # Decode a wire protocol unsigned integer at given offset and length and advance buffer pointer.
1750             sub decode_my_uint {
1751 0     0     my $buf = shift;
1752 0           my $pos = shift;
1753 0           my $nrbytes = shift;
1754              
1755 0           my @bytes = unpack('x' . $$pos . 'C' x $nrbytes, $buf);
1756 0           my $result = 0;
1757 0           for (my $i = 0; $i < $nrbytes; $i++) {
1758 0           $result += $bytes[$i] << ($i * 8);
1759             }
1760 0           $$pos += $nrbytes;
1761              
1762 0 0         return $result if $nrbytes <= Net::Wire10::MAX_UINT_SIZE;
1763              
1764 0 0 0       die 'Overflow while reading a large integer' if
1765             ($nrbytes > Net::Wire10::MAX_UINT_SIZE + 1) or
1766             ($bytes[-1] > 0x7f);
1767              
1768 0           return $result;
1769             }
1770              
1771             # Find the length of a LCB-coded unsigned integer and advance buffer pointer.
1772             sub decode_lcb_width {
1773 0     0     my $buf = shift;
1774 0           my $pos = shift;
1775 0           my $len = length($buf);
1776 0           my $msg = 'Reached end of input while decoding Length Coded Binary';
1777              
1778 0 0         die $msg if $$pos >= $len;
1779 0           my $head = ord substr(
1780             $buf,
1781             $$pos,
1782             UINT8_LENGTH
1783             );
1784              
1785 0 0         return UINT8_LENGTH if $head < LCB_NULL;
1786 0           $$pos += UINT8_LENGTH;
1787 0 0         return undef if $head == LCB_NULL;
1788 0           my $bytes = $LCB_LENGTHS[$head];
1789 0 0         die $msg if $$pos + $bytes >= $len;
1790 0 0         return $bytes if $head <= LCB_UINT64;
1791             # If we end up here, first byte equals 255, which is invalid.
1792 0           die 'Invalid First-Byte in Length Coded Binary: 255';
1793             }
1794              
1795             # Skip over a LCB-coded unsigned integer without decoding it.
1796             sub skip_lcb {
1797 0     0     my $buf = shift;
1798 0           my $pos = shift;
1799              
1800 0           my $bytes = decode_lcb_width($buf, $pos);
1801 0           my $my_uint = substr($buf, $$pos, $bytes);
1802 0           $$pos += $bytes;
1803 0           return $my_uint;
1804             }
1805              
1806             # Decode a wire protocol LCB-coded unsigned integer (length implicit) and advance buffer pointer.
1807             sub decode_lcb {
1808 0     0     my $buf = shift;
1809 0           my $pos = shift;
1810              
1811 0           my $bytes = decode_lcb_width($buf, $pos);
1812 0 0         return undef unless defined $bytes;
1813 0           return decode_my_uint($buf, $pos, $bytes);
1814             }
1815              
1816             # Get string and seek to the position after it
1817             sub decode_string {
1818 0     0     my $buf = shift;
1819 0           my $pos = shift;
1820              
1821 0           my $length = decode_lcb($buf, $pos);
1822              
1823             # Return some sort of a null indicator if the string is LCB_NULL.
1824 0 0         return undef unless defined $length;
1825              
1826             # Note: Neither the result set header, nor the column info packets, has
1827             # a field describing which character set the server has encoded the
1828             # metadata such as column names in. Also, the user can change the
1829             # character set used by issuing various SQL statements. In effect
1830             # making it impossible to know at this point in the state machine
1831             # which character set is being used without having either parsed user
1832             # queries or having done a "SELECT character_set_results" automatically
1833             # before each query is sent to the server.
1834              
1835 0           my $string = substr $buf, $$pos, $length;
1836 0           $$pos += $length;
1837 0           return $string;
1838             }
1839              
1840             # Skip string, seeking to the position after it
1841             sub skip_string {
1842 0     0     my $buf = shift;
1843 0           my $pos = shift;
1844              
1845 0           my $length = decode_lcb($buf, $pos);
1846              
1847             # Do nothing if string is LCB_NULL.
1848 0 0         $$pos += $length if defined $length;
1849              
1850 0           return undef;
1851             }
1852              
1853             # Note: The manual does not specify how the server handles small comments
1854             # terminating in CR, NEL, VT, FF, LS or PS. Only LF is recognized
1855             # below (a guess).
1856             # Note: The manual states that small comments initiated with -- must be
1857             # followed by a whitespace or similar such that an arithmetic double
1858             # minus is not mistaken for a comment, but it does not specify exactly
1859             # which characters are permitted. ASCII contol characters and the space
1860             # character are recognized below (a guess).
1861             # Note: The manual does not indicate whether ? tokens are allowed inside
1862             # conditional code such as /*!...*/. In the expression below
1863             # it is not allowed (a guess).
1864             # Note: The manual does not indicate which ASCII and Unicode characters are
1865             # considered whitespace. In the expression below, the ASCII characters
1866             # CR, LF, VT, HT, FF and 0x20 are recognized (a guess).
1867             my $split = qr/
1868             # capture each part, which is either:
1869             (
1870             # small comment in double-dash or
1871             --[[:cntrl:]\ ].*(?:\n|\z) |
1872             # small comment in hash or
1873             \#.*(?:\n|\z) |
1874             # big comment in C-style or version-conditional code or
1875             \/\*(?:[^\*]|\*[^\/])*(?:\*\/|\*\z|\z) |
1876             # whitespace
1877             [\ \r\n\013\t\f]+ |
1878             # single-quoted literal text or
1879             '(?:[^'\\]*|\\(?:.|\n)|'')*(?:'|\z) |
1880             # double-quoted literal text or
1881             "(?:[^"\\]*|\\(?:.|\n)|"")*(?:"|\z) |
1882             # schema-quoted literal text or
1883             `(?:[^`]*|``)*(?:`|\z) |
1884             # else it is either sql speak or
1885             (?:[^'"`\?\ \r\n\013\t\f\#\-\/]|\/[^\*]|-[^-]|--(?=[^[:cntrl:]\ ]))+ |
1886             # bingo: a ? placeholder
1887             \?
1888             )
1889             /x;
1890              
1891             # Split a MySQL-specific SQL string into parts,
1892             # looking for '?' prepared statement placeholders.
1893             sub tokenize {
1894 0     0     my $query = shift;
1895              
1896 0           my @tokens = $query =~ m/$split/g;
1897              
1898             # Assertion to ensure that bugs get caught; it's a bug
1899             # if the above regexp does not capture all of the query.
1900 0           my $parsed = join('', @tokens);
1901 0 0         die "query parsing failed" if length($parsed) != length($query);
1902              
1903 0           return @tokens;
1904             }
1905              
1906             sub quote {
1907 0     0     my $string = shift;
1908 0 0         return 'NULL' unless defined $string;
1909              
1910 0           for ($string) {
1911 0           s/\\/\\\\/g;
1912 0           s/\0/\\0/g;
1913 0           s/\n/\\n/g;
1914 0           s/\r/\\r/g;
1915 0           s/'/\\'/g;
1916 0           s/"/\\"/g;
1917 0           s/\x1a/\\Z/g;
1918             }
1919              
1920 0           return "'$string'";
1921             }
1922              
1923             sub quote_identifier {
1924 0     0     my $identifier = shift;
1925 0 0         return 'NULL' unless defined $identifier;
1926              
1927 0           for ($identifier) {
1928 0           s/`/``/g;
1929             }
1930              
1931 0           return "`$identifier`";
1932             }
1933              
1934             sub quote_wildcards {
1935 0     0     my $string = shift;
1936 0 0         return undef unless defined $string;
1937              
1938 0           for ($string) {
1939 0           s/%/\\%/g;
1940 0           s/_/\\_/g;
1941             }
1942              
1943 0           return $string;
1944             }
1945              
1946              
1947              
1948             package Net::Wire10::Password;
1949              
1950             #
1951             # Note: Neither Digest::SHA nor Digest::SHA1 are pure perl modules.
1952             # Digest::SHA::PurePerl exists, but is somewhat slow.
1953             #
1954             # TODO: Make use of if Digest::SHA1 is not available.
1955              
1956 1     1   7 use strict;
  1         2  
  1         39  
1957 1     1   6 use warnings;
  1         1  
  1         86  
1958              
1959             BEGIN {
1960             package Net::Wire10::Password;
1961              
1962             # Use C implementation of SHA if available (currently much faster).
1963 1     1   2 eval {
1964             # Note: Digest::SHA1 is used rather than Digest::SHA because the
1965             # former was in my tests slightly faster when processing
1966             # small amounts of data (such as passwords).
1967 1         1974 require Digest::SHA1;
1968 1         26271 Digest::SHA1->import("sha1");
1969             };
1970 1 50       378 if ($@) {
1971             # Otherwise fall back to the PurePerl implementation of SHA.
1972 0         0 require Digest::SHA::PurePerl;
1973 0         0 Digest::SHA::PurePerl->import("sha1");
1974             }
1975             }
1976              
1977             sub scramble {
1978 0     0     my $class = shift;
1979 0           my $password = shift;
1980 0           my $hash_seed = shift;
1981 0 0         return '' unless $password;
1982 0 0         return '' if length $password == 0;
1983 0           return _make_scrambled_password($hash_seed, $password);
1984             }
1985              
1986             sub _make_scrambled_password {
1987 0     0     my $hash_seed = shift;
1988 0           my $password = shift;
1989              
1990 0           my $stage1 = sha1($password);
1991 0           my $stage2 = sha1($stage1);
1992 0           my $result = sha1($hash_seed . $stage2);
1993              
1994 0           return _my_crypt($result, $stage1);
1995             }
1996              
1997             sub _my_crypt {
1998 0     0     my $s1 = shift;
1999 0           my $s2 = shift;
2000 0           my $l = length($s1) - 1;
2001 0           my $result = '';
2002 0           for my $i (0..$l) {
2003 0           $result .= pack 'C', (unpack('C', substr($s1, $i, 1)) ^ unpack('C', substr($s2, $i, 1)));
2004             }
2005 0           return $result;
2006             }
2007              
2008              
2009              
2010             package Net::Wire10::Password32;
2011              
2012 1     1   15 use strict;
  1         2  
  1         86  
2013 1     1   6 use warnings;
  1         9  
  1         1540  
2014              
2015             sub scramble {
2016 0     0     my $class = shift;
2017 0           my $password = shift;
2018 0           my $hash_seed = shift;
2019 0           my $client_capabilities = shift;
2020              
2021 0 0         return '' unless $password;
2022 0 0         return '' if length $password == 0;
2023              
2024 0           my $hsl = length $hash_seed;
2025 0           my @out;
2026 0           my @hash_pass = _get_hash($password);
2027 0           my @hash_mess = _get_hash($hash_seed);
2028              
2029 0           my ($max_value, $seed, $seed2);
2030 0           my ($dRes, $dSeed, $dMax);
2031 0 0         if ($client_capabilities < 1) {
2032 0           $max_value = 0x01FFFFFF;
2033 0           $seed = _xor_by_long($hash_pass[0], $hash_mess[0]) % $max_value;
2034 0           $seed2 = int($seed / 2);
2035             } else {
2036 0           $max_value= 0x3FFFFFFF;
2037 0           $seed = _xor_by_long($hash_pass[0], $hash_mess[0]) % $max_value;
2038 0           $seed2 = _xor_by_long($hash_pass[1], $hash_mess[1]) % $max_value;
2039             }
2040 0           $dMax = $max_value;
2041              
2042 0           for (my $i=0; $i < $hsl; $i++) {
2043 0           $seed = int(($seed * 3 + $seed2) % $max_value);
2044 0           $seed2 = int(($seed + $seed2 + 33) % $max_value);
2045 0           $dSeed = $seed;
2046 0           $dRes = $dSeed / $dMax;
2047 0           push @out, int($dRes * 31) + 64;
2048             }
2049              
2050 0 0         if ($client_capabilities == 1) {
2051             # Make it harder to break
2052 0           $seed = ($seed * 3 + $seed2 ) % $max_value;
2053 0           $seed2 = ($seed + $seed2 + 33 ) % $max_value;
2054 0           $dSeed = $seed;
2055              
2056 0           $dRes = $dSeed / $dMax;
2057 0           my $e = int($dRes * 31);
2058 0           for (my $i=0; $i < $hsl ; $i++) {
2059 0           $out[$i] ^= $e;
2060             }
2061             }
2062 0           return join '', map { chr $_ } @out;
  0            
2063             }
2064              
2065             sub _get_hash {
2066 0     0     my $password = shift;
2067              
2068 0           my $nr = 1345345333;
2069 0           my $add = 7;
2070 0           my $nr2 = 0x12345671;
2071 0           my $tmp;
2072 0           my $pwlen = length $password;
2073 0           my $c;
2074              
2075 0           for (my $i=0; $i < $pwlen; $i++) {
2076 0           my $c = substr $password, $i, 1;
2077 0 0 0       next if $c eq ' ' || $c eq "\t";
2078 0           my $tmp = ord $c;
2079 0           my $value = ((_and_by_char($nr, 63) + $add) * $tmp) + $nr * 256;
2080 0           $nr = _xor_by_long($nr, $value);
2081 0           $nr2 += _xor_by_long(($nr2 * 256), $nr);
2082 0           $add += $tmp;
2083             }
2084 0           return (_and_by_long($nr, 0x7fffffff), _and_by_long($nr2, 0x7fffffff));
2085             }
2086              
2087             sub _and_by_char {
2088 0     0     my $source = shift;
2089 0           my $mask = shift;
2090              
2091 0           return $source & $mask;
2092             }
2093              
2094             sub _and_by_long {
2095 0     0     my $source = shift;
2096 0   0       my $mask = shift || 0xFFFFFFFF;
2097              
2098 0           return _cut_off_to_long($source) & _cut_off_to_long($mask);
2099             }
2100              
2101             sub _xor_by_long {
2102 0     0     my $source = shift;
2103 0   0       my $mask = shift || 0;
2104              
2105 0           return _cut_off_to_long($source) ^ _cut_off_to_long($mask);
2106             }
2107              
2108             sub _cut_off_to_long {
2109 0     0     my $source = shift;
2110              
2111 0 0         if ($] >= 5.006) {
2112 0 0         $source = $source % (0xFFFFFFFF + 1) if $source > 0xFFFFFFFF;
2113 0           return $source;
2114             }
2115 0           while ($source > 0xFFFFFFFF) {
2116 0           $source -= 0xFFFFFFFF + 1;
2117             }
2118 0           return $source;
2119             }
2120              
2121              
2122             1;
2123             __END__