File Coverage

blib/lib/DBIx/Oracle/UpgradeUtf8.pm
Criterion Covered Total %
statement 14 56 25.0
branch 0 30 0.0
condition 0 26 0.0
subroutine 5 10 50.0
pod 2 3 66.6
total 21 125 16.8


line stmt bran cond sub pod time code
1 1     1   85741 use 5.10.0;
  1         4  
2             package DBIx::Oracle::UpgradeUtf8;
3 1     1   5 use utf8;
  1         3  
  1         8  
4 1     1   25 use strict;
  1         2  
  1         18  
5 1     1   4 use warnings;
  1         2  
  1         27  
6 1     1   5 use Scalar::Util qw/looks_like_number/;
  1         2  
  1         820  
7              
8             our $VERSION = 1.01;
9              
10             my @default_dbh_methods = qw/do
11             prepare
12             selectrow_array
13             selectrow_arrayref
14             selectrow_hashref
15             selectall_arrayref
16             selectall_array
17             selectall_hashref
18             selectcol_arrayref/;
19              
20             my @default_sth_methods = qw/bind_param
21             bind_param_array
22             execute
23             execute_array/;
24              
25             sub new {
26 0     0 1   my ($class, %options) = @_;
27              
28             # check validity of args
29 0           my $error = __PACKAGE__ . "->new()";
30 0 0 0       for ($options{debug}) {!$_ or ref $_ eq 'CODE' or die "$error: 'debug' should be a coderef"}
  0            
31 0 0 0       for ($options{dbh_methods}) {!$_ or ref $_ eq 'ARRAY' or die "$error: 'dbh_methods' should be an arrayref"}
  0            
32 0 0 0       for ($options{sth_methods}) {!$_ or ref $_ eq 'ARRAY' or die "$error: 'sth_methods' should be an arrayref"}
  0            
33              
34             # build object internals
35             my $self = {
36             debug => delete $options{debug},
37             dbh_methods => delete $options{dbh_methods} // \@default_dbh_methods,
38 0   0       sth_methods => delete $options{sth_methods} // \@default_sth_methods,
      0        
39             };
40              
41             # check that all options have been consumed
42 0           my @invalid_options = keys %options;
43 0 0         die "$error: invalid options : " . join " / ", @invalid_options if @invalid_options;
44              
45             # return object
46 0           bless $self, $class;
47             }
48              
49              
50             sub inject_callbacks {
51 0     0 1   my ($self, $dbh, @invalid_args) = @_;
52              
53             # check input args
54 0 0         $dbh->isa('DBI::db') or die '->inject_callbacks() : arg is not a database handle';
55 0 0         !@invalid_args or die '->inject_callbacks() : too many args';
56              
57             # coderef to be installed as common callback for all methods. This is a closure on $debug.
58 0           my $debug = $self->{debug}; # Copy for easier reference. The coderef will be a closure on $debug.
59             my $upgrade_string_args = sub {
60 0 0   0     $debug->("$_ callback") if $debug; # Note: $_ is the method name
61              
62             # all strings in @_ will be upgraded (in-place, not copies)
63             ARG:
64 0           foreach my $i (1 .. $#_) { # start only at 1 because $_[0] is the DBI handle
65              
66             # if arg is undef or empty string or 0, there is nothing to do
67 0 0         next ARG if !$_[$i];
68              
69             # if arg is a scalar and is a native string, upgrade it
70 0 0         if (! ref $_[$i]) {
    0          
71 0 0 0       next ARG if looks_like_number($_[$i]) or utf8::is_utf8($_[$i]);
72 0 0         $debug->("upgrading arg [$i] ($_[$i])") if $debug;
73 0           utf8::upgrade($_[$i]);
74             }
75              
76             # if arg is an arrayref (used by the *_array methods), upgrade native strings in that array
77             elsif (ref $_[$i] eq 'ARRAY') {
78 0 0 0       for my $val (grep {$_ && !ref $_ && !looks_like_number($_) && !utf8::is_utf8($_)} @{$_[$i]}) {
  0   0        
  0            
79 0 0         $debug->("upgrading string in array arg [$i] ($val)") if $debug;
80 0           utf8::upgrade($val);
81             }
82             }
83             }
84              
85 0           return; # must end with an empty return (see L documentation)
86 0           };
87              
88             # inject callbacks for $dbh methods and for $sth methods
89 0   0       my $parent_callbacks = $dbh->{Callbacks} //= {};
90 0   0       my $child_callbacks = $parent_callbacks->{ChildCallbacks} //= {};
91 0           inject_callback($parent_callbacks, $_ => $upgrade_string_args) for @{$self->{dbh_methods}};
  0            
92 0           inject_callback($child_callbacks, $_ => $upgrade_string_args) for @{$self->{sth_methods}};
  0            
93             }
94              
95              
96             sub inject_callback {
97 0     0 0   my ($hash, $key, $coderef) = @_;
98              
99             # in case a previous callback was already installed, we replace it with a sub that combines both
100 0           my $previous_cb = $hash->{$key};
101 0 0   0     my $new_cb = $previous_cb ? sub {&$coderef; &$previous_cb} : $coderef;
  0            
  0            
102              
103 0           $hash->{$key} = $new_cb;
104             }
105              
106             1;
107              
108              
109             __END__