line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::MySQL; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
15709
|
use 5.004; |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
85
|
|
4
|
2
|
|
|
2
|
|
2208
|
use IO::Socket; |
|
2
|
|
|
|
|
105197
|
|
|
2
|
|
|
|
|
10
|
|
5
|
2
|
|
|
2
|
|
2483
|
use Carp; |
|
2
|
|
|
|
|
12
|
|
|
2
|
|
|
|
|
119
|
|
6
|
2
|
|
|
2
|
|
10
|
use vars qw($VERSION $DEBUG); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
397
|
|
7
|
2
|
|
|
2
|
|
10
|
use strict; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
120
|
|
8
|
|
|
|
|
|
|
$VERSION = '0.11'; |
9
|
|
|
|
|
|
|
|
10
|
2
|
|
|
2
|
|
11
|
use constant COMMAND_SLEEP => "\x00"; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
409
|
|
11
|
2
|
|
|
2
|
|
10
|
use constant COMMAND_QUIT => "\x01"; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
106
|
|
12
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_INIT_DB => "\x02"; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
128
|
|
13
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_QUERY => "\x03"; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
96
|
|
14
|
2
|
|
|
2
|
|
21
|
use constant COMMAND_FIELD_LIST => "\x04"; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
81
|
|
15
|
2
|
|
|
2
|
|
10
|
use constant COMMAND_CREATE_DB => "\x05"; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
87
|
|
16
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_DROP_DB => "\x06"; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
83
|
|
17
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_REFRESH => "\x07"; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
85
|
|
18
|
2
|
|
|
2
|
|
19
|
use constant COMMAND_SHUTDOWN => "\x08"; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
205
|
|
19
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_STATISTICS => "\x09"; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
89
|
|
20
|
2
|
|
|
2
|
|
8
|
use constant COMMAND_PROCESS_INFO => "\x0A"; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
79
|
|
21
|
2
|
|
|
2
|
|
8
|
use constant COMMAND_CONNECT => "\x0B"; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
182
|
|
22
|
2
|
|
|
2
|
|
10
|
use constant COMMAND_PROCESS_KILL => "\x0C"; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
82
|
|
23
|
2
|
|
|
2
|
|
10
|
use constant COMMAND_DEBUG => "\x0D"; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
79
|
|
24
|
2
|
|
|
2
|
|
8
|
use constant COMMAND_PING => "\x0E"; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
154
|
|
25
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_TIME => "\x0F"; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
88
|
|
26
|
2
|
|
|
2
|
|
8
|
use constant COMMAND_DELAYED_INSERT => "\x10"; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
108
|
|
27
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_CHANGE_USER => "\x11"; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
83
|
|
28
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_BINLOG_DUMP => "\x12"; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
126
|
|
29
|
2
|
|
|
2
|
|
10
|
use constant COMMAND_TABLE_DUMP => "\x13"; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
85
|
|
30
|
2
|
|
|
2
|
|
9
|
use constant COMMAND_CONNECT_OUT => "\x14"; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
79
|
|
31
|
|
|
|
|
|
|
|
32
|
2
|
|
|
2
|
|
8
|
use constant DEFAULT_PORT_NUMBER => 3306; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
80
|
|
33
|
2
|
|
|
2
|
|
10
|
use constant BUFFER_LENGTH => 1460; |
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
73
|
|
34
|
2
|
|
|
2
|
|
10
|
use constant DEFAULT_UNIX_SOCKET => '/tmp/mysql.sock'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
8238
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub new |
38
|
|
|
|
|
|
|
{ |
39
|
0
|
|
|
0
|
1
|
0
|
my $class = shift; |
40
|
0
|
|
|
|
|
0
|
my %args = @_; |
41
|
|
|
|
|
|
|
|
42
|
0
|
|
0
|
|
|
0
|
my $self = bless { |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
43
|
|
|
|
|
|
|
hostname => $args{hostname}, |
44
|
|
|
|
|
|
|
unixsocket => $args{unixsocket} || DEFAULT_UNIX_SOCKET, |
45
|
|
|
|
|
|
|
port => $args{port} || DEFAULT_PORT_NUMBER, |
46
|
|
|
|
|
|
|
database => $args{database}, |
47
|
|
|
|
|
|
|
user => $args{user}, |
48
|
|
|
|
|
|
|
password => $args{password}, |
49
|
|
|
|
|
|
|
timeout => $args{timeout} || 60, |
50
|
|
|
|
|
|
|
'socket' => undef, |
51
|
|
|
|
|
|
|
salt => '', |
52
|
|
|
|
|
|
|
protocol_version => undef, |
53
|
|
|
|
|
|
|
client_capabilities => 0, |
54
|
|
|
|
|
|
|
affected_rows_length => 0, |
55
|
|
|
|
|
|
|
}, $class; |
56
|
0
|
|
|
|
|
0
|
$self->debug($args{debug}); |
57
|
0
|
|
|
|
|
0
|
$self->_initialize; |
58
|
0
|
|
|
|
|
0
|
return $self; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub query |
63
|
|
|
|
|
|
|
{ |
64
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
65
|
0
|
|
|
|
|
0
|
my $sql = join '', @_; |
66
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
67
|
|
|
|
|
|
|
|
68
|
0
|
|
|
|
|
0
|
return $self->_execute_command(COMMAND_QUERY, $sql); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub create_database |
73
|
|
|
|
|
|
|
{ |
74
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
75
|
0
|
|
|
|
|
0
|
my $db_name = shift; |
76
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
77
|
|
|
|
|
|
|
|
78
|
0
|
|
|
|
|
0
|
return $self->_execute_command(COMMAND_CREATE_DB, $db_name); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub drop_database |
83
|
|
|
|
|
|
|
{ |
84
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
85
|
0
|
|
|
|
|
0
|
my $db_name = shift; |
86
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
87
|
|
|
|
|
|
|
|
88
|
0
|
|
|
|
|
0
|
return $self->_execute_command(COMMAND_DROP_DB, $db_name); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub close |
93
|
|
|
|
|
|
|
{ |
94
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
95
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
96
|
0
|
0
|
|
|
|
0
|
return unless $mysql->can('send'); |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
0
|
my $quit_message = |
99
|
|
|
|
|
|
|
chr(length(COMMAND_QUIT)). "\x00\x00\x00". COMMAND_QUIT; |
100
|
0
|
|
|
|
|
0
|
$mysql->send($quit_message, 0); |
101
|
0
|
0
|
|
|
|
0
|
$self->_dump_packet($quit_message) if Net::MySQL->debug; |
102
|
0
|
|
|
|
|
0
|
$mysql->close; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub get_affected_rows_length |
107
|
|
|
|
|
|
|
{ |
108
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
109
|
0
|
|
|
|
|
0
|
$self->{affected_rows_length}; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub get_insert_id |
114
|
|
|
|
|
|
|
{ |
115
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
116
|
0
|
|
|
|
|
0
|
$self->{insert_id}; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub create_record_iterator |
121
|
|
|
|
|
|
|
{ |
122
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
123
|
0
|
0
|
|
|
|
0
|
return undef unless $self->has_selected_record; |
124
|
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
0
|
my $record = Net::MySQL::RecordIterator->new( |
126
|
|
|
|
|
|
|
$self->{selected_record} |
127
|
|
|
|
|
|
|
); |
128
|
0
|
|
|
|
|
0
|
$self->{selected_record} = undef; |
129
|
0
|
|
|
|
|
0
|
$record->parse; |
130
|
0
|
|
|
|
|
0
|
return $record; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub has_selected_record |
135
|
|
|
|
|
|
|
{ |
136
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
137
|
0
|
0
|
|
|
|
0
|
$self->{selected_record} ? 1 : undef; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub is_error |
142
|
|
|
|
|
|
|
{ |
143
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
144
|
0
|
0
|
|
|
|
0
|
$self->{error_code} ? 1 : undef; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub get_error_code |
149
|
|
|
|
|
|
|
{ |
150
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
151
|
0
|
|
|
|
|
0
|
$self->{error_code}; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub get_error_message |
156
|
|
|
|
|
|
|
{ |
157
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
158
|
0
|
|
|
|
|
0
|
$self->{server_message}; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub debug |
163
|
|
|
|
|
|
|
{ |
164
|
0
|
|
|
0
|
1
|
0
|
my $class = shift; |
165
|
0
|
0
|
|
|
|
0
|
$DEBUG = shift if @_; |
166
|
0
|
|
|
|
|
0
|
$DEBUG; |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub _connect |
171
|
|
|
|
|
|
|
{ |
172
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
173
|
|
|
|
|
|
|
|
174
|
0
|
|
|
|
|
0
|
my $mysql; |
175
|
0
|
0
|
|
|
|
0
|
if ($self->{hostname}) { |
176
|
0
|
0
|
|
|
|
0
|
printf "Use INET Socket: %s %d/tcp\n", $self->{hostname}, $self->{port} |
177
|
|
|
|
|
|
|
if $self->debug; |
178
|
0
|
0
|
0
|
|
|
0
|
$mysql = IO::Socket::INET->new( |
179
|
|
|
|
|
|
|
PeerAddr => $self->{hostname}, |
180
|
|
|
|
|
|
|
PeerPort => $self->{port}, |
181
|
|
|
|
|
|
|
Proto => 'tcp', |
182
|
|
|
|
|
|
|
Timeout => $self->{timeout} || 60, |
183
|
|
|
|
|
|
|
) or croak "Couldn't connect to $self->{hostname}:$self->{port}/tcp: $@"; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
else { |
186
|
0
|
0
|
|
|
|
0
|
printf "Use UNIX Socket: %s\n", $self->{unixsocket} if $self->debug; |
187
|
0
|
0
|
|
|
|
0
|
$mysql = IO::Socket::UNIX->new( |
188
|
|
|
|
|
|
|
Type => SOCK_STREAM, |
189
|
|
|
|
|
|
|
Peer => $self->{unixsocket}, |
190
|
|
|
|
|
|
|
) or croak "Couldn't connect to $self->{unixsocket}: $@"; |
191
|
|
|
|
|
|
|
} |
192
|
0
|
|
|
|
|
0
|
$mysql->autoflush(1); |
193
|
0
|
|
|
|
|
0
|
$self->{socket} = $mysql; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub _get_server_information |
198
|
|
|
|
|
|
|
{ |
199
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
200
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
201
|
|
|
|
|
|
|
|
202
|
0
|
|
|
|
|
0
|
my $message; |
203
|
0
|
|
|
|
|
0
|
$mysql->recv($message, BUFFER_LENGTH, 0); |
204
|
0
|
0
|
|
|
|
0
|
$self->_dump_packet($message) |
205
|
|
|
|
|
|
|
if Net::MySQL->debug; |
206
|
0
|
|
|
|
|
0
|
my $i = 0; |
207
|
0
|
|
|
|
|
0
|
my $packet_length = ord substr $message, $i, 1; |
208
|
0
|
|
|
|
|
0
|
$i += 4; |
209
|
0
|
|
|
|
|
0
|
$self->{protocol_version} = ord substr $message, $i, 1; |
210
|
0
|
0
|
|
|
|
0
|
printf "Protocol Version: %d\n", $self->{protocol_version} |
211
|
|
|
|
|
|
|
if Net::MySQL->debug; |
212
|
0
|
0
|
|
|
|
0
|
if ($self->{protocol_version} == 10) { |
213
|
0
|
|
|
|
|
0
|
$self->{client_capabilities} = 1; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
0
|
++$i; |
217
|
0
|
|
|
|
|
0
|
my $string_end = index($message, "\0", $i) - $i; |
218
|
0
|
|
|
|
|
0
|
$self->{server_version} = substr $message, $i, $string_end; |
219
|
0
|
0
|
|
|
|
0
|
printf "Server Version: %s\n", $self->{server_version} |
220
|
|
|
|
|
|
|
if Net::MySQL->debug; |
221
|
|
|
|
|
|
|
|
222
|
0
|
|
|
|
|
0
|
$i += $string_end + 1; |
223
|
0
|
|
|
|
|
0
|
$self->{server_thread_id} = unpack 'v', substr $message, $i, 2; |
224
|
0
|
|
|
|
|
0
|
$i += 4; |
225
|
0
|
|
|
|
|
0
|
$self->{salt} = substr $message, $i, 8; |
226
|
|
|
|
|
|
|
# |
227
|
0
|
|
|
|
|
0
|
$i += 8+1; |
228
|
0
|
0
|
|
|
|
0
|
if (length $message >= $i + 1) { |
229
|
0
|
|
|
|
|
0
|
$i += 1; |
230
|
|
|
|
|
|
|
} |
231
|
0
|
0
|
|
|
|
0
|
if (length $message >= $i + 18) { |
232
|
|
|
|
|
|
|
# get server_language |
233
|
|
|
|
|
|
|
# get server_status |
234
|
|
|
|
|
|
|
} |
235
|
0
|
|
|
|
|
0
|
$i += 18 - 1; |
236
|
0
|
0
|
|
|
|
0
|
if (length $message >= $i + 12 - 1) { |
237
|
0
|
|
|
|
|
0
|
$self->{salt} .= substr $message, $i, 12; |
238
|
|
|
|
|
|
|
} |
239
|
0
|
0
|
|
|
|
0
|
printf "Salt: %s\n", $self->{salt} if Net::MySQL->debug; |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub _request_authentication |
245
|
|
|
|
|
|
|
{ |
246
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
247
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
248
|
0
|
|
|
|
|
0
|
$self->_send_login_message(); |
249
|
|
|
|
|
|
|
|
250
|
0
|
|
|
|
|
0
|
my $auth_result; |
251
|
0
|
|
|
|
|
0
|
$mysql->recv($auth_result, BUFFER_LENGTH, 0); |
252
|
0
|
0
|
|
|
|
0
|
$self->_dump_packet($auth_result) if Net::MySQL->debug; |
253
|
0
|
0
|
|
|
|
0
|
if ($self->_is_error($auth_result)) { |
254
|
0
|
|
|
|
|
0
|
$mysql->close; |
255
|
0
|
0
|
|
|
|
0
|
if (length $auth_result < 7) { |
256
|
0
|
|
|
|
|
0
|
croak "Timeout of authentication"; |
257
|
|
|
|
|
|
|
} |
258
|
0
|
|
|
|
|
0
|
croak substr $auth_result, 7; |
259
|
|
|
|
|
|
|
} |
260
|
0
|
0
|
|
|
|
0
|
print "connect database\n" if Net::MySQL->debug; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
sub _send_login_message |
265
|
|
|
|
|
|
|
{ |
266
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
267
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
268
|
0
|
|
|
|
|
0
|
my $body = "\0\0\x01\x0d\xa6\03\0\0\0\0\x01". |
269
|
|
|
|
|
|
|
"\x21\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0". |
270
|
|
|
|
|
|
|
join "\0", |
271
|
|
|
|
|
|
|
$self->{user}, |
272
|
|
|
|
|
|
|
"\x14". |
273
|
|
|
|
|
|
|
Net::MySQL::Password->scramble( |
274
|
|
|
|
|
|
|
$self->{password}, $self->{salt}, $self->{client_capabilities} |
275
|
|
|
|
|
|
|
); |
276
|
0
|
|
|
|
|
0
|
$body .= $self->{database}; |
277
|
0
|
|
|
|
|
0
|
$body .= "\0"; |
278
|
0
|
|
|
|
|
0
|
my $login_message = chr(length($body)-3). $body; |
279
|
0
|
|
|
|
|
0
|
$mysql->send($login_message, 0); |
280
|
0
|
0
|
|
|
|
0
|
$self->_dump_packet($login_message) if Net::MySQL->debug; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub _execute_command |
286
|
|
|
|
|
|
|
{ |
287
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
288
|
0
|
|
|
|
|
0
|
my $command = shift; |
289
|
0
|
|
|
|
|
0
|
my $sql = shift; |
290
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
291
|
|
|
|
|
|
|
|
292
|
0
|
|
|
|
|
0
|
my $message = pack('V', length($sql) + 1). $command. $sql; |
293
|
0
|
|
|
|
|
0
|
$mysql->send($message, 0); |
294
|
0
|
0
|
|
|
|
0
|
$self->_dump_packet($message) if Net::MySQL->debug; |
295
|
|
|
|
|
|
|
|
296
|
0
|
|
|
|
|
0
|
my $result; |
297
|
0
|
|
|
|
|
0
|
$mysql->recv($result, BUFFER_LENGTH, 0); |
298
|
0
|
0
|
|
|
|
0
|
$self->_dump_packet($result) if Net::MySQL->debug; |
299
|
0
|
|
|
|
|
0
|
$self->_reset_status; |
300
|
|
|
|
|
|
|
|
301
|
0
|
0
|
|
|
|
0
|
if ($self->_is_error($result)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
302
|
0
|
|
|
|
|
0
|
return $self->_set_error_by_packet($result); |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
elsif ($self->_is_select_query_result($result)) { |
305
|
0
|
|
|
|
|
0
|
return $self->_get_record_by_server($result); |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
elsif ($self->_is_update_query_result($result)){ |
308
|
0
|
|
|
|
|
0
|
return $self->_get_affected_rows_information_by_packet($result); |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
else { |
311
|
0
|
|
|
|
|
0
|
croak 'Unknown Result: '. $self->_get_result_length($result). 'byte'; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub _initialize |
317
|
|
|
|
|
|
|
{ |
318
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
319
|
0
|
|
|
|
|
0
|
$self->_connect; |
320
|
0
|
|
|
|
|
0
|
$self->_get_server_information; |
321
|
0
|
|
|
|
|
0
|
$self->_request_authentication; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub _set_error_by_packet |
326
|
|
|
|
|
|
|
{ |
327
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
328
|
0
|
|
|
|
|
0
|
my $packet = shift; |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
0
|
my $error_message = $self->_get_server_message($packet); |
331
|
0
|
|
|
|
|
0
|
$self->{server_message} = $error_message; |
332
|
0
|
|
|
|
|
0
|
$self->{error_code} = $self->_get_error_code($packet); |
333
|
0
|
|
|
|
|
0
|
return undef; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
sub _get_record_by_server |
338
|
|
|
|
|
|
|
{ |
339
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
340
|
0
|
|
|
|
|
0
|
my $packet = shift; |
341
|
0
|
|
|
|
|
0
|
my $mysql = $self->{socket}; |
342
|
0
|
|
|
|
|
0
|
$self->_get_column_length($packet); |
343
|
0
|
|
|
|
|
0
|
while ($self->_has_next_packet($packet)) { |
344
|
0
|
|
|
|
|
0
|
my $next_result; |
345
|
0
|
|
|
|
|
0
|
$mysql->recv($next_result, BUFFER_LENGTH, 0); |
346
|
0
|
|
|
|
|
0
|
$packet .= $next_result; |
347
|
0
|
0
|
|
|
|
0
|
$self->_dump_packet($next_result) if Net::MySQL->debug; |
348
|
|
|
|
|
|
|
} |
349
|
0
|
|
|
|
|
0
|
$self->{selected_record} = $packet; |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub _get_affected_rows_information_by_packet |
354
|
|
|
|
|
|
|
{ |
355
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
356
|
0
|
|
|
|
|
0
|
my $packet = shift; |
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
|
|
0
|
$self->{affected_rows_length} = $self->_get_affected_rows_length($packet); |
359
|
0
|
|
|
|
|
0
|
$self->{insert_id} = $self->_get_insert_id($packet); |
360
|
0
|
|
|
|
|
0
|
$self->{server_message} = $self->_get_server_message($packet); |
361
|
0
|
|
|
|
|
0
|
return $self->{affected_rows_length}; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub _is_error |
366
|
|
|
|
|
|
|
{ |
367
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
368
|
0
|
|
|
|
|
0
|
my $packet = shift; |
369
|
0
|
0
|
|
|
|
0
|
return 1 if length $packet < 4; |
370
|
0
|
|
|
|
|
0
|
ord(substr $packet, 4) == 255; |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
sub _is_select_query_result |
375
|
|
|
|
|
|
|
{ |
376
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
377
|
0
|
|
|
|
|
0
|
my $packet = shift; |
378
|
0
|
0
|
|
|
|
0
|
return undef if $self->_is_error($packet); |
379
|
0
|
|
|
|
|
0
|
ord(substr $packet, 4) >= 1; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub _is_update_query_result |
384
|
|
|
|
|
|
|
{ |
385
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
386
|
0
|
|
|
|
|
0
|
my $packet = shift; |
387
|
0
|
0
|
|
|
|
0
|
return undef if $self->_is_error($packet); |
388
|
0
|
|
|
|
|
0
|
ord(substr $packet, 4) == 0; |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub _get_result_length |
393
|
|
|
|
|
|
|
{ |
394
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
395
|
0
|
|
|
|
|
0
|
my $packet = shift; |
396
|
0
|
|
|
|
|
0
|
ord(substr $packet, 0, 1) |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
sub _get_column_length |
401
|
|
|
|
|
|
|
{ |
402
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
403
|
0
|
|
|
|
|
0
|
my $packet = shift; |
404
|
0
|
|
|
|
|
0
|
ord(substr $packet, 4); |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub _get_affected_rows_length |
409
|
|
|
|
|
|
|
{ |
410
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
411
|
0
|
|
|
|
|
0
|
my $packet = shift; |
412
|
0
|
|
|
|
|
0
|
my $pos = 5; |
413
|
0
|
|
|
|
|
0
|
return Net::MySQL::Util::get_field_length($packet, \$pos); |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
sub _get_insert_id |
418
|
|
|
|
|
|
|
{ |
419
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
420
|
0
|
|
|
|
|
0
|
my $packet = shift; |
421
|
0
|
0
|
|
|
|
0
|
return ord(substr $packet, 6, 1) if ord(substr $packet, 6, 1) != 0xfc; |
422
|
0
|
|
|
|
|
0
|
unpack 'v', substr $packet, 7, 2; |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
sub _get_server_message |
427
|
|
|
|
|
|
|
{ |
428
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
429
|
0
|
|
|
|
|
0
|
my $packet = shift; |
430
|
0
|
0
|
|
|
|
0
|
return '' if length $packet < 7; |
431
|
0
|
|
|
|
|
0
|
substr $packet, 7; |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub _get_error_code |
436
|
|
|
|
|
|
|
{ |
437
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
438
|
0
|
|
|
|
|
0
|
my $packet = shift; |
439
|
0
|
0
|
|
|
|
0
|
$self->_is_error($packet) |
440
|
|
|
|
|
|
|
or croak "_get_error_code(): Is not error packet"; |
441
|
0
|
|
|
|
|
0
|
unpack 'v', substr $packet, 5, 2; |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub _reset_status |
446
|
|
|
|
|
|
|
{ |
447
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
448
|
0
|
|
|
|
|
0
|
$self->{insert_id} = 0; |
449
|
0
|
|
|
|
|
0
|
$self->{server_message} = ''; |
450
|
0
|
|
|
|
|
0
|
$self->{error_code} = undef; |
451
|
0
|
|
|
|
|
0
|
$self->{selected_record} = undef; |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
sub _has_next_packet |
456
|
|
|
|
|
|
|
{ |
457
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
458
|
|
|
|
|
|
|
#substr($_[0], -1) ne "\xfe"; |
459
|
|
|
|
|
|
|
#$self->_dump_packet(substr($_[0], -5)); |
460
|
0
|
|
|
|
|
0
|
return substr($_[0], -5, 1) ne "\xfe"; |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
sub _dump_packet { |
465
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
466
|
0
|
|
|
|
|
0
|
my $packet = shift; |
467
|
0
|
|
|
|
|
0
|
my ($method_name) = (caller(1))[3]; |
468
|
0
|
|
|
|
|
0
|
my $str = sprintf "%s():\n", $method_name; |
469
|
0
|
|
|
|
|
0
|
while ($packet =~ /(.{1,16})/sg) { |
470
|
0
|
|
|
|
|
0
|
my $line = $1; |
471
|
0
|
|
|
|
|
0
|
$str .= join ' ', map {sprintf '%02X', ord $_} split //, $line; |
|
0
|
|
|
|
|
0
|
|
472
|
0
|
|
|
|
|
0
|
$str .= ' ' x (16 - length $line); |
473
|
0
|
|
|
|
|
0
|
$str .= ' '; |
474
|
0
|
0
|
|
|
|
0
|
$str .= join '', map { |
475
|
0
|
|
|
|
|
0
|
sprintf '%s', (/[\w\d\*\,\?\%\=\'\;\(\)\.-]/) ? $_ : '.' |
476
|
|
|
|
|
|
|
} split //, $line; |
477
|
0
|
|
|
|
|
0
|
$str .= "\n"; |
478
|
|
|
|
|
|
|
} |
479
|
0
|
|
|
|
|
0
|
print $str; |
480
|
|
|
|
|
|
|
#warn $str; |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
package Net::MySQL::RecordIterator; |
486
|
2
|
|
|
2
|
|
22
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
144
|
|
487
|
|
|
|
|
|
|
|
488
|
2
|
|
|
2
|
|
10
|
use constant NULL_COLUMN => 251; |
|
2
|
|
|
|
|
19
|
|
|
2
|
|
|
|
|
212
|
|
489
|
2
|
|
|
2
|
|
10
|
use constant UNSIGNED_CHAR_COLUMN => 251; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
170
|
|
490
|
2
|
|
|
2
|
|
9
|
use constant UNSIGNED_SHORT_COLUMN => 252; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
85
|
|
491
|
2
|
|
|
2
|
|
11
|
use constant UNSIGNED_INT24_COLUMN => 253; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
71
|
|
492
|
2
|
|
|
2
|
|
10
|
use constant UNSIGNED_INT32_COLUMN => 254; |
|
2
|
|
|
|
|
23
|
|
|
2
|
|
|
|
|
75
|
|
493
|
2
|
|
|
2
|
|
10
|
use constant UNSIGNED_CHAR_LENGTH => 1; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
90
|
|
494
|
2
|
|
|
2
|
|
9
|
use constant UNSIGNED_SHORT_LENGTH => 2; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
120
|
|
495
|
2
|
|
|
2
|
|
10
|
use constant UNSIGNED_INT24_LENGTH => 3; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
87
|
|
496
|
2
|
|
|
2
|
|
47
|
use constant UNSIGNED_INT32_LENGTH => 4; |
|
2
|
|
|
|
|
12
|
|
|
2
|
|
|
|
|
80
|
|
497
|
2
|
|
|
2
|
|
8
|
use constant UNSIGNED_INT32_PAD_LENGTH => 4; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
3313
|
|
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
sub new |
501
|
|
|
|
|
|
|
{ |
502
|
0
|
|
|
0
|
|
0
|
my $class = shift; |
503
|
0
|
|
|
|
|
0
|
my $packet = shift; |
504
|
0
|
|
|
|
|
0
|
bless { |
505
|
|
|
|
|
|
|
packet => $packet, |
506
|
|
|
|
|
|
|
position => 0, |
507
|
|
|
|
|
|
|
column => [], |
508
|
|
|
|
|
|
|
}, $class; |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
sub parse |
513
|
|
|
|
|
|
|
{ |
514
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
515
|
0
|
|
|
|
|
0
|
$self->_get_column_length; |
516
|
0
|
|
|
|
|
0
|
$self->_get_column_name; |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
sub each |
521
|
|
|
|
|
|
|
{ |
522
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
523
|
0
|
|
|
|
|
0
|
my @result; |
524
|
0
|
0
|
|
|
|
0
|
return undef if $self->is_end_of_packet; |
525
|
|
|
|
|
|
|
|
526
|
0
|
|
|
|
|
0
|
for (1..$self->{column_length}) { |
527
|
0
|
|
|
|
|
0
|
push @result, $self->_get_string_and_seek_position; |
528
|
|
|
|
|
|
|
} |
529
|
0
|
|
|
|
|
0
|
$self->{position} += 4; |
530
|
|
|
|
|
|
|
|
531
|
0
|
|
|
|
|
0
|
return \@result; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
sub is_end_of_packet |
536
|
|
|
|
|
|
|
{ |
537
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
538
|
0
|
|
|
|
|
0
|
return substr($self->{packet}, $self->{position}, 1) eq "\xFE"; |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
sub get_field_length |
543
|
|
|
|
|
|
|
{ |
544
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
545
|
0
|
|
|
|
|
0
|
$self->{column_length}; |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
sub get_field_names |
550
|
|
|
|
|
|
|
{ |
551
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
552
|
0
|
|
|
|
|
0
|
map { $_->{column} } @{$self->{column}}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
sub _get_column_length |
557
|
|
|
|
|
|
|
{ |
558
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
559
|
0
|
|
|
|
|
0
|
$self->{position} += 4; |
560
|
0
|
|
|
|
|
0
|
$self->{column_length} = ord substr $self->{packet}, $self->{position}, 1; |
561
|
0
|
|
|
|
|
0
|
$self->{position} += 5; |
562
|
0
|
0
|
|
|
|
0
|
printf "Column Length: %d\n", $self->{column_length} |
563
|
|
|
|
|
|
|
if Net::MySQL->debug; |
564
|
|
|
|
|
|
|
} |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
sub _get_column_name |
568
|
|
|
|
|
|
|
{ |
569
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
570
|
|
|
|
|
|
|
|
571
|
0
|
|
|
|
|
0
|
for my $i (1.. $self->{column_length}) { |
572
|
0
|
|
|
|
|
0
|
$self->_get_string_and_seek_position; |
573
|
0
|
|
|
|
|
0
|
$self->_get_string_and_seek_position; |
574
|
0
|
|
|
|
|
0
|
my $table = $self->_get_string_and_seek_position; |
575
|
0
|
|
|
|
|
0
|
$self->_get_string_and_seek_position; |
576
|
0
|
|
|
|
|
0
|
my $column = $self->_get_string_and_seek_position; |
577
|
0
|
|
|
|
|
0
|
$self->_get_string_and_seek_position; |
578
|
0
|
|
|
|
|
0
|
push @{$self->{column}}, { |
|
0
|
|
|
|
|
0
|
|
579
|
|
|
|
|
|
|
table => $table, |
580
|
|
|
|
|
|
|
column => $column, |
581
|
|
|
|
|
|
|
}; |
582
|
0
|
|
|
|
|
0
|
$self->_get_string_and_seek_position; |
583
|
0
|
|
|
|
|
0
|
$self->{position} += 4; |
584
|
|
|
|
|
|
|
} |
585
|
0
|
|
|
|
|
0
|
$self->{position} += 9; |
586
|
0
|
|
|
|
|
0
|
printf "Column name: '%s'\n", |
587
|
0
|
0
|
|
|
|
0
|
join ", ", map { $_->{column} } @{$self->{column}} |
|
0
|
|
|
|
|
0
|
|
588
|
|
|
|
|
|
|
if Net::MySQL->debug; |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
sub _get_string_and_seek_position |
593
|
|
|
|
|
|
|
{ |
594
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
595
|
|
|
|
|
|
|
|
596
|
0
|
|
|
|
|
0
|
my $length = $self->_get_field_length(); |
597
|
|
|
|
|
|
|
|
598
|
0
|
0
|
|
|
|
0
|
return undef unless defined $length; |
599
|
|
|
|
|
|
|
|
600
|
0
|
|
|
|
|
0
|
my $string = substr $self->{packet}, $self->{position}, $length; |
601
|
0
|
|
|
|
|
0
|
$self->{position} += $length; |
602
|
0
|
|
|
|
|
0
|
return $string; |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
sub _get_field_length |
607
|
|
|
|
|
|
|
{ |
608
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
609
|
0
|
|
|
|
|
0
|
return Net::MySQL::Util::get_field_length($self->{packet}, \$self->{position}); |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
package Net::MySQL::Util; |
614
|
2
|
|
|
2
|
|
15
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
66
|
|
615
|
|
|
|
|
|
|
|
616
|
2
|
|
|
2
|
|
10
|
use constant NULL_COLUMN => 251; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
100
|
|
617
|
2
|
|
|
2
|
|
9
|
use constant UNSIGNED_CHAR_COLUMN => 251; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
74
|
|
618
|
2
|
|
|
2
|
|
10
|
use constant UNSIGNED_SHORT_COLUMN => 252; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
76
|
|
619
|
2
|
|
|
2
|
|
7
|
use constant UNSIGNED_INT24_COLUMN => 253; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
90
|
|
620
|
2
|
|
|
2
|
|
10
|
use constant UNSIGNED_INT32_COLUMN => 254; |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
260
|
|
621
|
2
|
|
|
2
|
|
10
|
use constant UNSIGNED_CHAR_LENGTH => 1; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
288
|
|
622
|
2
|
|
|
2
|
|
13
|
use constant UNSIGNED_SHORT_LENGTH => 2; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
88
|
|
623
|
2
|
|
|
2
|
|
10
|
use constant UNSIGNED_INT24_LENGTH => 3; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
76
|
|
624
|
2
|
|
|
2
|
|
9
|
use constant UNSIGNED_INT32_LENGTH => 4; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
83
|
|
625
|
2
|
|
|
2
|
|
11
|
use constant UNSIGNED_INT32_PAD_LENGTH => 4; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
959
|
|
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub get_field_length |
629
|
|
|
|
|
|
|
{ |
630
|
0
|
|
|
0
|
|
0
|
my $packet = shift; |
631
|
0
|
|
|
|
|
0
|
my $pos = shift; |
632
|
|
|
|
|
|
|
|
633
|
0
|
|
|
|
|
0
|
my $head = ord substr( |
634
|
|
|
|
|
|
|
$packet, |
635
|
|
|
|
|
|
|
$$pos, |
636
|
|
|
|
|
|
|
UNSIGNED_CHAR_LENGTH |
637
|
|
|
|
|
|
|
); |
638
|
0
|
|
|
|
|
0
|
$$pos += UNSIGNED_CHAR_LENGTH; |
639
|
|
|
|
|
|
|
|
640
|
0
|
0
|
|
|
|
0
|
return undef if $head == NULL_COLUMN; |
641
|
0
|
0
|
|
|
|
0
|
if ($head < UNSIGNED_CHAR_COLUMN) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
642
|
0
|
|
|
|
|
0
|
return $head; |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
elsif ($head == UNSIGNED_SHORT_COLUMN) { |
645
|
0
|
|
|
|
|
0
|
my $length = unpack 'v', substr( |
646
|
|
|
|
|
|
|
$packet, |
647
|
|
|
|
|
|
|
$$pos, |
648
|
|
|
|
|
|
|
UNSIGNED_SHORT_LENGTH |
649
|
|
|
|
|
|
|
); |
650
|
0
|
|
|
|
|
0
|
$$pos += UNSIGNED_SHORT_LENGTH; |
651
|
0
|
|
|
|
|
0
|
return $length; |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
elsif ($head == UNSIGNED_INT24_COLUMN) { |
654
|
0
|
|
|
|
|
0
|
my $int24 = substr( |
655
|
|
|
|
|
|
|
$packet, $$pos, |
656
|
|
|
|
|
|
|
UNSIGNED_INT24_LENGTH |
657
|
|
|
|
|
|
|
); |
658
|
0
|
|
|
|
|
0
|
my $length = unpack('C', substr($int24, 0, 1)) |
659
|
|
|
|
|
|
|
+ (unpack('C', substr($int24, 1, 1)) << 8) |
660
|
|
|
|
|
|
|
+ (unpack('C', substr($int24, 2, 1)) << 16); |
661
|
0
|
|
|
|
|
0
|
$$pos += UNSIGNED_INT24_LENGTH; |
662
|
0
|
|
|
|
|
0
|
return $length; |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
else { |
665
|
0
|
|
|
|
|
0
|
my $int32 = substr( |
666
|
|
|
|
|
|
|
$packet, $$pos, |
667
|
|
|
|
|
|
|
UNSIGNED_INT32_LENGTH |
668
|
|
|
|
|
|
|
); |
669
|
0
|
|
|
|
|
0
|
my $length = unpack('C', substr($int32, 0, 1)) |
670
|
|
|
|
|
|
|
+ (unpack('C', substr($int32, 1, 1)) << 8) |
671
|
|
|
|
|
|
|
+ (unpack('C', substr($int32, 2, 1)) << 16) |
672
|
|
|
|
|
|
|
+ (unpack('C', substr($int32, 3, 1)) << 24); |
673
|
0
|
|
|
|
|
0
|
$$pos += UNSIGNED_INT32_LENGTH; |
674
|
0
|
|
|
|
|
0
|
$$pos += UNSIGNED_INT32_PAD_LENGTH; |
675
|
0
|
|
|
|
|
0
|
return $length; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
package Net::MySQL::Password; |
682
|
2
|
|
|
2
|
|
12
|
use strict; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
55
|
|
683
|
2
|
|
|
2
|
|
2276
|
use Digest::SHA1; |
|
2
|
|
|
|
|
2334
|
|
|
2
|
|
|
|
|
940
|
|
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
sub scramble { |
686
|
0
|
|
|
0
|
|
0
|
my $class = shift; |
687
|
0
|
|
|
|
|
0
|
my $password = shift; |
688
|
0
|
|
|
|
|
0
|
my $hash_seed = shift; |
689
|
0
|
0
|
|
|
|
0
|
return '' unless $password; |
690
|
0
|
0
|
|
|
|
0
|
return '' if length $password == 0; |
691
|
0
|
|
|
|
|
0
|
return _make_scrambled_password($hash_seed, $password); |
692
|
|
|
|
|
|
|
} |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
sub _make_scrambled_password { |
696
|
0
|
|
|
0
|
|
0
|
my $message = shift; |
697
|
0
|
|
|
|
|
0
|
my $password = shift; |
698
|
|
|
|
|
|
|
|
699
|
0
|
|
|
|
|
0
|
my $ctx = Digest::SHA1->new; |
700
|
0
|
|
|
|
|
0
|
$ctx->reset; |
701
|
0
|
|
|
|
|
0
|
$ctx->add($password); |
702
|
0
|
|
|
|
|
0
|
my $stage1 = $ctx->digest; |
703
|
|
|
|
|
|
|
|
704
|
0
|
|
|
|
|
0
|
$ctx->reset; |
705
|
0
|
|
|
|
|
0
|
$ctx->add($stage1); |
706
|
0
|
|
|
|
|
0
|
my $stage2 = $ctx->digest; |
707
|
|
|
|
|
|
|
|
708
|
0
|
|
|
|
|
0
|
$ctx->reset; |
709
|
0
|
|
|
|
|
0
|
$ctx->add($message); |
710
|
0
|
|
|
|
|
0
|
$ctx->add($stage2); |
711
|
0
|
|
|
|
|
0
|
my $result = $ctx->digest; |
712
|
0
|
|
|
|
|
0
|
return _my_crypt($result, $stage1); |
713
|
|
|
|
|
|
|
} |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
sub _my_crypt { |
716
|
0
|
|
|
0
|
|
0
|
my $s1 = shift; |
717
|
0
|
|
|
|
|
0
|
my $s2 = shift; |
718
|
0
|
|
|
|
|
0
|
my $l = length($s1) - 1; |
719
|
0
|
|
|
|
|
0
|
my $result = ''; |
720
|
0
|
|
|
|
|
0
|
for my $i (0..$l) { |
721
|
0
|
|
|
|
|
0
|
$result .= pack 'C', (unpack('C', substr($s1, $i, 1)) ^ unpack('C', substr($s2, $i, 1))); |
722
|
|
|
|
|
|
|
} |
723
|
0
|
|
|
|
|
0
|
return $result; |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
package Net::MySQL::Password32; |
727
|
2
|
|
|
2
|
|
14
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1624
|
|
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
sub scramble |
730
|
|
|
|
|
|
|
{ |
731
|
4
|
|
|
4
|
|
16
|
my $class = shift; |
732
|
4
|
|
|
|
|
7
|
my $password = shift; |
733
|
4
|
|
|
|
|
5
|
my $hash_seed = shift; |
734
|
4
|
|
|
|
|
5
|
my $client_capabilities = shift; |
735
|
|
|
|
|
|
|
|
736
|
4
|
100
|
|
|
|
18
|
return '' unless $password; |
737
|
2
|
50
|
|
|
|
6
|
return '' if length $password == 0; |
738
|
|
|
|
|
|
|
|
739
|
2
|
|
|
|
|
3
|
my $hsl = length $hash_seed; |
740
|
2
|
|
|
|
|
3
|
my @out; |
741
|
2
|
|
|
|
|
5
|
my @hash_pass = _get_hash($password); |
742
|
2
|
|
|
|
|
3
|
my @hash_mess = _get_hash($hash_seed); |
743
|
|
|
|
|
|
|
|
744
|
2
|
|
|
|
|
3
|
my ($max_value, $seed, $seed2); |
745
|
0
|
|
|
|
|
0
|
my ($dRes, $dSeed, $dMax); |
746
|
2
|
100
|
|
|
|
6
|
if ($client_capabilities < 1) { |
747
|
1
|
|
|
|
|
1
|
$max_value = 0x01FFFFFF; |
748
|
1
|
|
|
|
|
3
|
$seed = _xor_by_long($hash_pass[0], $hash_mess[0]) % $max_value; |
749
|
1
|
|
|
|
|
2
|
$seed2 = int($seed / 2); |
750
|
|
|
|
|
|
|
} else { |
751
|
1
|
|
|
|
|
1
|
$max_value= 0x3FFFFFFF; |
752
|
1
|
|
|
|
|
3
|
$seed = _xor_by_long($hash_pass[0], $hash_mess[0]) % $max_value; |
753
|
1
|
|
|
|
|
4
|
$seed2 = _xor_by_long($hash_pass[1], $hash_mess[1]) % $max_value; |
754
|
|
|
|
|
|
|
} |
755
|
2
|
|
|
|
|
3
|
$dMax = $max_value; |
756
|
|
|
|
|
|
|
|
757
|
2
|
|
|
|
|
6
|
for (my $i=0; $i < $hsl; $i++) { |
758
|
16
|
|
|
|
|
16
|
$seed = int(($seed * 3 + $seed2) % $max_value); |
759
|
16
|
|
|
|
|
15
|
$seed2 = int(($seed + $seed2 + 33) % $max_value); |
760
|
16
|
|
|
|
|
15
|
$dSeed = $seed; |
761
|
16
|
|
|
|
|
22
|
$dRes = $dSeed / $dMax; |
762
|
16
|
|
|
|
|
35
|
push @out, int($dRes * 31) + 64; |
763
|
|
|
|
|
|
|
} |
764
|
|
|
|
|
|
|
|
765
|
2
|
100
|
|
|
|
5
|
if ($client_capabilities == 1) { |
766
|
|
|
|
|
|
|
# Make it harder to break |
767
|
1
|
|
|
|
|
3
|
$seed = ($seed * 3 + $seed2 ) % $max_value; |
768
|
1
|
|
|
|
|
2
|
$seed2 = ($seed + $seed2 + 33 ) % $max_value; |
769
|
1
|
|
|
|
|
2
|
$dSeed = $seed; |
770
|
|
|
|
|
|
|
|
771
|
1
|
|
|
|
|
2
|
$dRes = $dSeed / $dMax; |
772
|
1
|
|
|
|
|
2
|
my $e = int($dRes * 31); |
773
|
1
|
|
|
|
|
4
|
for (my $i=0; $i < $hsl ; $i++) { |
774
|
8
|
|
|
|
|
14
|
$out[$i] ^= $e; |
775
|
|
|
|
|
|
|
} |
776
|
|
|
|
|
|
|
} |
777
|
2
|
|
|
|
|
5
|
return join '', map { chr $_ } @out; |
|
16
|
|
|
|
|
36
|
|
778
|
|
|
|
|
|
|
} |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
sub _get_hash |
782
|
|
|
|
|
|
|
{ |
783
|
4
|
|
|
4
|
|
5
|
my $password = shift; |
784
|
|
|
|
|
|
|
|
785
|
4
|
|
|
|
|
4
|
my $nr = 1345345333; |
786
|
4
|
|
|
|
|
15
|
my $add = 7; |
787
|
4
|
|
|
|
|
4
|
my $nr2 = 0x12345671; |
788
|
4
|
|
|
|
|
5
|
my $tmp; |
789
|
4
|
|
|
|
|
3
|
my $pwlen = length $password; |
790
|
4
|
|
|
|
|
4
|
my $c; |
791
|
|
|
|
|
|
|
|
792
|
4
|
|
|
|
|
12
|
for (my $i=0; $i < $pwlen; $i++) { |
793
|
36
|
|
|
|
|
45
|
my $c = substr $password, $i, 1; |
794
|
36
|
50
|
33
|
|
|
123
|
next if $c eq ' ' || $c eq "\t"; |
795
|
36
|
|
|
|
|
36
|
my $tmp = ord $c; |
796
|
36
|
|
|
|
|
97
|
my $value = ((_and_by_char($nr, 63) + $add) * $tmp) + $nr * 256; |
797
|
36
|
|
|
|
|
46
|
$nr = _xor_by_long($nr, $value); |
798
|
36
|
|
|
|
|
59
|
$nr2 += _xor_by_long(($nr2 * 256), $nr); |
799
|
36
|
|
|
|
|
71
|
$add += $tmp; |
800
|
|
|
|
|
|
|
} |
801
|
4
|
|
|
|
|
6
|
return (_and_by_long($nr, 0x7fffffff), _and_by_long($nr2, 0x7fffffff)); |
802
|
|
|
|
|
|
|
} |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
sub _and_by_char |
806
|
|
|
|
|
|
|
{ |
807
|
36
|
|
|
36
|
|
32
|
my $source = shift; |
808
|
36
|
|
|
|
|
30
|
my $mask = shift; |
809
|
|
|
|
|
|
|
|
810
|
36
|
|
|
|
|
60
|
return $source & $mask; |
811
|
|
|
|
|
|
|
} |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
sub _and_by_long |
815
|
|
|
|
|
|
|
{ |
816
|
8
|
|
|
8
|
|
9
|
my $source = shift; |
817
|
8
|
|
50
|
|
|
14
|
my $mask = shift || 0xFFFFFFFF; |
818
|
|
|
|
|
|
|
|
819
|
8
|
|
|
|
|
9
|
return _cut_off_to_long($source) & _cut_off_to_long($mask); |
820
|
|
|
|
|
|
|
} |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
sub _xor_by_long |
824
|
|
|
|
|
|
|
{ |
825
|
75
|
|
|
75
|
|
66
|
my $source = shift; |
826
|
75
|
|
50
|
|
|
126
|
my $mask = shift || 0; |
827
|
|
|
|
|
|
|
|
828
|
75
|
|
|
|
|
86
|
return _cut_off_to_long($source) ^ _cut_off_to_long($mask); |
829
|
|
|
|
|
|
|
} |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
sub _cut_off_to_long |
833
|
|
|
|
|
|
|
{ |
834
|
166
|
|
|
166
|
|
134
|
my $source = shift; |
835
|
|
|
|
|
|
|
|
836
|
166
|
50
|
|
|
|
242
|
if ($] >= 5.006) { |
837
|
166
|
100
|
|
|
|
236
|
$source = $source % (0xFFFFFFFF + 1) if $source > 0xFFFFFFFF; |
838
|
166
|
|
|
|
|
251
|
return $source; |
839
|
|
|
|
|
|
|
} |
840
|
0
|
|
|
|
|
|
while ($source > 0xFFFFFFFF) { |
841
|
0
|
|
|
|
|
|
$source -= 0xFFFFFFFF + 1; |
842
|
|
|
|
|
|
|
} |
843
|
0
|
|
|
|
|
|
return $source; |
844
|
|
|
|
|
|
|
} |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
1; |
848
|
|
|
|
|
|
|
__END__ |