File Coverage

blib/lib/DBD/mysqlPP.pm
Criterion Covered Total %
statement 56 226 24.7
branch 11 100 11.0
condition 11 25 44.0
subroutine 13 34 38.2
pod 0 1 0.0
total 91 386 23.5


line stmt bran cond sub pod time code
1             package DBD::mysqlPP;
2 2     2   96522 use strict;
  2         4  
  2         69  
3              
4 2     2   2267 use DBI;
  2         18875  
  2         107  
5 2     2   27 use Carp;
  2         3  
  2         121  
6 2     2   9 use vars qw($VERSION $err $errstr $state $drh);
  2         3  
  2         963  
7              
8             $VERSION = '0.07';
9             $err = 0;
10             $errstr = '';
11             $state = undef;
12             $drh = undef;
13              
14             sub driver
15             {
16 1 50   1 0 178 return $drh if $drh;
17              
18 1         4 my $class = shift;
19 1         2 my $attr = shift;
20 1         2 $class .= '::dr';
21              
22 1         11 $drh = DBI::_new_drh($class, {
23             Name => 'mysqlPP',
24             Version => $VERSION,
25             Err => \$DBD::mysqlPP::err,
26             Errstr => \$DBD::mysqlPP::errstr,
27             State => \$DBD::mysqlPP::state,
28             Attribution => 'DBD::mysqlPP by Hiroyuki OYAMA',
29             }, {});
30             }
31              
32              
33             sub _parse_dsn
34             {
35 0     0   0 my $class = shift;
36 0         0 my ($dsn, $args) = @_;
37 0         0 my($hash, $var, $val);
38 0 0       0 return if ! defined $dsn;
39              
40 0         0 while (length $dsn) {
41 0 0       0 if ($dsn =~ /([^:;]*)[:;](.*)/) {
42 0         0 $val = $1;
43 0         0 $dsn = $2;
44             }
45             else {
46 0         0 $val = $dsn;
47 0         0 $dsn = '';
48             }
49 0 0       0 if ($val =~ /([^=]*)=(.*)/) {
50 0         0 $var = $1;
51 0         0 $val = $2;
52 0 0 0     0 if ($var eq 'hostname' || $var eq 'host') {
    0 0        
53 0         0 $hash->{'host'} = $val;
54             }
55             elsif ($var eq 'db' || $var eq 'dbname') {
56 0         0 $hash->{'database'} = $val;
57             }
58             else {
59 0         0 $hash->{$var} = $val;
60             }
61             }
62             else {
63 0         0 for $var (@$args) {
64 0 0       0 if (!defined($hash->{$var})) {
65 0         0 $hash->{$var} = $val;
66 0         0 last;
67             }
68             }
69             }
70             }
71 0         0 return $hash;
72             }
73              
74              
75             sub _parse_dsn_host
76             {
77 0     0   0 my($class, $dsn) = @_;
78 0         0 my $hash = $class->_parse_dsn($dsn, ['host', 'port']);
79 0         0 ($hash->{'host'}, $hash->{'port'});
80             }
81              
82              
83              
84             package DBD::mysqlPP::dr;
85              
86             $DBD::mysqlPP::dr::imp_data_size = 0;
87              
88 2     2   992 use Net::MySQL;
  2         47009  
  2         52  
89 2     2   13 use strict;
  2         2  
  2         426  
90              
91              
92             sub connect
93             {
94 0     0   0 my $drh = shift;
95 0         0 my ($dsn, $user, $password, $attrhash) = @_;
96              
97 0         0 my $data_source_info = DBD::mysqlPP->_parse_dsn(
98             $dsn, ['database', 'host', 'port'],
99             );
100 0   0     0 $user ||= '';
101 0   0     0 $password ||= '';
102              
103 0         0 my $dbh = DBI::_new_dbh($drh, {
104             Name => $dsn,
105             USER => $user,
106             CURRENT_USRE => $user,
107             }, {});
108 0         0 eval {
109 0         0 my $mysql = Net::MySQL->new(
110             hostname => $data_source_info->{host},
111             port => $data_source_info->{port},
112             database => $data_source_info->{database},
113             user => $user,
114             password => $password,
115             debug => $attrhash->{protocol_dump},
116             );
117 0         0 $dbh->STORE(mysqlpp_connection => $mysql);
118 0         0 $dbh->STORE(thread_id => $mysql->{server_thread_id});
119             };
120 0 0       0 if ($@) {
121 0         0 return $dbh->DBI::set_err(1, $@);
122             }
123 0         0 return $dbh;
124             }
125              
126              
127             sub data_sources
128             {
129 0     0   0 return ("dbi:mysqlPP:");
130             }
131              
132              
133 1     1   875 sub disconnect_all {}
134              
135              
136              
137             package DBD::mysqlPP::db;
138              
139             $DBD::mysqlPP::db::imp_data_size = 0;
140 2     2   11 use strict;
  2         2  
  2         2337  
141              
142              
143             # Patterns referred to 'mysql_sub_escape_string()' of libmysql.c
144             sub quote
145             {
146 9     9   14 my $dbh = shift;
147 9         11 my ($statement, $type) = @_;
148 9 100       16 return 'NULL' unless defined $statement;
149              
150 8         12 for ($statement) {
151 8         11 s/\\/\\\\/g;
152 8         9 s/\0/\\0/g;
153 8         10 s/\n/\\n/g;
154 8         7 s/\r/\\r/g;
155 8         6 s/'/\\'/g;
156 8         8 s/"/\\"/g;
157 8         16 s/\x1a/\\Z/g;
158             }
159 8         23 return "'$statement'";
160             }
161              
162             sub _count_param
163             {
164 0     0   0 my @statement = split //, shift;
165 0         0 my $num = 0;
166              
167 0         0 while (defined(my $c = shift @statement)) {
168 0 0 0     0 if ($c eq '"' || $c eq "'") {
    0          
169 0         0 my $end = $c;
170 0         0 while (defined(my $c = shift @statement)) {
171 0 0       0 last if $c eq $end;
172 0 0       0 @statement = splice @statement, 2 if $c eq '\\';
173             }
174             }
175             elsif ($c eq '?') {
176 0         0 $num++;
177             }
178             }
179 0         0 return $num;
180             }
181              
182             sub prepare
183             {
184 0     0   0 my $dbh = shift;
185 0         0 my ($statement, @attribs) = @_;
186              
187 0         0 my $sth = DBI::_new_sth($dbh, {
188             Statement => $statement,
189             });
190 0         0 $sth->STORE(mysqlpp_handle => $dbh->FETCH('mysqlpp_connection'));
191 0         0 $sth->STORE(mysqlpp_params => []);
192 0         0 $sth->STORE(NUM_OF_PARAMS => _count_param($statement));
193 0         0 $sth;
194             }
195              
196              
197             sub commit
198             {
199 0     0   0 my $dbh = shift;
200 0 0       0 if ($dbh->FETCH('Warn')) {
201 0         0 warn 'Commit ineffective while AutoCommit is on';
202             }
203 0         0 1;
204             }
205              
206              
207             sub rollback
208             {
209 0     0   0 my $dbh = shift;
210 0 0       0 if ($dbh->FETCH('Warn')) {
211 0         0 warn 'Rollback ineffective while AutoCommit is on';
212             }
213 0         0 1;
214             }
215              
216              
217             sub tables
218             {
219 0     0   0 my $dbh = shift;
220 0         0 my @args = @_;
221 0         0 my $mysql = $dbh->FETCH('mysqlpp_connection');
222              
223 0         0 my @database_list;
224 0         0 eval {
225 0         0 $mysql->query('show tables');
226 0 0       0 die $mysql->get_error_message if $mysql->is_error;
227 0 0       0 if ($mysql->has_selected_record) {
228 0         0 my $record = $mysql->create_record_iterator;
229 0         0 while (my $db_name = $record->each) {
230 0         0 push @database_list, $db_name->[0];
231             }
232             }
233             };
234 0 0       0 if ($@) {
235 0         0 warn $mysql->get_error_message;
236             }
237 0 0       0 return $mysql->is_error
238             ? undef
239             : @database_list;
240             }
241              
242              
243             sub _ListDBs
244             {
245 0     0   0 my $dbh = shift;
246 0         0 my @args = @_;
247 0         0 my $mysql = $dbh->FETCH('mysqlpp_connection');
248              
249 0         0 my @database_list;
250 0         0 eval {
251 0         0 $mysql->query('show databases');
252 0 0       0 die $mysql->get_error_message if $mysql->is_error;
253 0 0       0 if ($mysql->has_selected_record) {
254 0         0 my $record = $mysql->create_record_iterator;
255 0         0 while (my $db_name = $record->each) {
256 0         0 push @database_list, $db_name->[0];
257             }
258             }
259             };
260 0 0       0 if ($@) {
261 0         0 warn $mysql->get_error_message;
262             }
263 0 0       0 return $mysql->is_error
264             ? undef
265             : @database_list;
266             }
267              
268              
269             sub _ListTables
270             {
271 0     0   0 my $dbh = shift;
272 0         0 return $dbh->tables;
273             }
274              
275              
276             sub disconnect
277             {
278 0     0   0 return 1;
279             }
280              
281              
282             sub FETCH
283             {
284 0     0   0 my $dbh = shift;
285 0         0 my $key = shift;
286              
287 0 0       0 return 1 if $key eq 'AutoCommit';
288 0 0       0 return $dbh->{$key} if $key =~ /^(?:mysqlpp_.*|thread_id|mysql_insertid)$/;
289 0         0 return $dbh->SUPER::FETCH($key);
290             }
291              
292              
293             sub STORE
294             {
295 0     0   0 my $dbh = shift;
296 0         0 my ($key, $value) = @_;
297              
298 0 0       0 if ($key eq 'AutoCommit') {
    0          
299 0 0       0 die "Can't disable AutoCommit" unless $value;
300 0         0 return 1;
301             }
302             elsif ($key =~ /^(?:mysqlpp_.*|thread_id|mysql_insertid)$/) {
303 0         0 $dbh->{$key} = $value;
304 0         0 return 1;
305             }
306 0         0 return $dbh->SUPER::STORE($key, $value);
307             }
308              
309              
310             sub DESTROY
311             {
312 0     0   0 my $dbh = shift;
313 0         0 my $mysql = $dbh->FETCH('mysqlpp_connection');
314 0         0 $mysql->close;
315             }
316              
317              
318             package DBD::mysqlPP::st;
319              
320             $DBD::mysqlPP::st::imp_data_size = 0;
321 2     2   12 use strict;
  2         3  
  2         2038  
322              
323              
324             sub bind_param
325             {
326 0     0   0 my $sth = shift;
327 0         0 my ($index, $value, $attr) = @_;
328 0 0       0 my $type = (ref $attr) ? $attr->{TYPE} : $attr;
329 0 0       0 if ($type) {
330 0         0 my $dbh = $sth->{Database};
331 0         0 $value = $dbh->quote($sth, $type);
332             }
333 0         0 my $params = $sth->FETCH('mysqlpp_param');
334 0         0 $params->[$index - 1] = $value;
335             }
336              
337              
338              
339             sub execute
340             {
341 0     0   0 my $sth = shift;
342 0         0 my @bind_values = @_;
343 0 0       0 my $params = (@bind_values) ?
344             \@bind_values : $sth->FETCH('mysqlpp_params');
345 0         0 my $num_param = $sth->FETCH('NUM_OF_PARAMS');
346 0 0       0 if (@$params != $num_param) {
347             # ...
348             }
349 0         0 my $statement = _mysqlpp_bind_statement($sth, $params);
350             #warn $statement;
351              
352 0         0 my $mysql = $sth->FETCH('mysqlpp_handle');
353 0         0 my $result = eval {
354 0         0 $sth->{mysqlpp_record_iterator} = undef;
355 0         0 $mysql->query($statement);
356 0 0       0 die if $mysql->is_error;
357              
358 0         0 my $dbh = $sth->{Database};
359 0         0 $dbh->STORE(mysqlpp_insertid => $mysql->get_insert_id);
360 0         0 $dbh->STORE(mysql_insertid => $mysql->get_insert_id);
361              
362 0         0 $sth->{mysqlpp_rows} = $mysql->get_affected_rows_length;
363 0 0       0 if ($mysql->has_selected_record) {
364 0         0 my $record = $mysql->create_record_iterator;
365 0         0 $sth->{mysqlpp_record_iterator} = $record;
366 0         0 $sth->STORE(NUM_OF_FIELDS => $record->get_field_length);
367 0         0 $sth->STORE(NAME => [ $record->get_field_names ]);
368             }
369 0         0 $mysql->get_affected_rows_length;
370             };
371 0 0       0 if ($@) {
372 0         0 $sth->DBI::set_err(
373             $mysql->get_error_code, $mysql->get_error_message
374             );
375 0         0 return undef;
376             }
377              
378 0 0       0 return $mysql->is_error
    0          
379             ? undef : $result
380             ? $result : '0E0';
381             }
382              
383              
384             sub fetch
385             {
386 0     0   0 my $sth = shift;
387              
388 0         0 my $iterator = $sth->FETCH('mysqlpp_record_iterator');
389 0         0 my $row = $iterator->each;
390 0 0       0 return undef unless $row;
391              
392 0 0       0 if ($sth->FETCH('ChopBlanks')) {
393 0         0 map {s/\s+$//} @$row;
  0         0  
394             }
395 0         0 return $sth->_set_fbav($row);
396             }
397             *fetchrow_arrayref = \&fetch;
398              
399              
400             sub rows
401             {
402 0     0   0 my $sth = shift;
403 0         0 $sth->FETCH('mysqlpp_rows');
404             }
405              
406              
407             sub FETCH
408             {
409 0     0   0 my $dbh = shift;
410 0         0 my $key = shift;
411              
412 0 0       0 return 1 if $key eq 'AutoCommit';
413 0 0       0 return $dbh->{NAME} if $key eq 'NAME';
414 0 0       0 return $dbh->{$key} if $key =~ /^mysqlpp_/;
415 0         0 return $dbh->SUPER::FETCH($key);
416             }
417              
418              
419             sub STORE
420             {
421 0     0   0 my $dbh = shift;
422 0         0 my ($key, $value) = @_;
423              
424 0 0       0 if ($key eq 'AutoCommit') {
    0          
    0          
425 0 0       0 die "Can't disable AutoCommit" unless $value;
426 0         0 return 1;
427             }
428             elsif ($key eq 'NAME') {
429 0         0 $dbh->{NAME} = $value;
430 0         0 return 1;
431             }
432             elsif ($key =~ /^mysqlpp_/) {
433 0         0 $dbh->{$key} = $value;
434 0         0 return 1;
435             }
436 0         0 return $dbh->SUPER::STORE($key, $value);
437             }
438              
439             sub _mysqlpp_bind_statement {
440 8     8   94 my ($sth, $params) = @_;
441              
442 8         136 my @splitted = split qr/((?:\?)|(?:\bLIMIT\b))/i, $sth->{Statement};
443 8         19 my $param_idx = 0;
444 8         9 my $limit_found = 0;
445 8         23 for (my $i=0; $i<@splitted; $i++ ) {
446 38         51 my $dbh = $sth->{Database};
447 38 100 100     265 if ( $splitted[$i] eq '?' && exists $params->[$param_idx] ) {
    100          
448 13 100 66     70 my $value = $limit_found && $params->[$param_idx] =~ qr/^\d+$/ ? $params->[$param_idx++] #bind for LIMIT isn't need quote
449             : $dbh->quote($params->[$param_idx++]);
450 13         22 $splitted[$i] = $value;
451 13 100 100     99 if ( exists $splitted[$i + 1]
      100        
452             && $splitted[$i + 1] !~ qr/,/ # qr/,/ is for LIMIT ?, ?
453             && $splitted[$i + 1] !~ qr/\bOFFSET\b/i ) {
454 2         7 $limit_found = 0;
455             }
456             }
457             elsif( $splitted[$i] =~ qr/\bLIMIT\b/i ) {
458 3         45 $limit_found = 1;
459             }
460             }
461 8         32 return join '', @splitted;
462             }
463              
464             sub DESTROY
465             {
466 8     8   3996 my $dbh = shift;
467              
468             }
469              
470              
471             1;
472             __END__