File Coverage

blib/lib/Apache/Session/Browseable/DBI.pm
Criterion Covered Total %
statement 101 140 72.1
branch 27 58 46.5
condition 6 17 35.2
subroutine 11 15 73.3
pod 0 4 0.0
total 145 234 61.9


line stmt bran cond sub pod time code
1             package Apache::Session::Browseable::DBI;
2              
3 4     4   21444 use strict;
  4         9  
  4         154  
4              
5 4     4   40 use DBI;
  4         10  
  4         169  
6 4     4   544 use Apache::Session;
  4         1851  
  4         86  
7 4     4   1717 use Apache::Session::Browseable::_common;
  4         12  
  4         2285  
8              
9             our $VERSION = '1.3.9';
10             our @ISA = qw(Apache::Session Apache::Session::Browseable::_common);
11              
12             sub searchOn {
13 6     6 0 16958 my $class = shift;
14 6         17 my ( $args, $selectField, $value, @fields ) = @_;
15              
16             # Escape quotes
17 6         19 $selectField =~ s/'/''/g;
18 6 100       26 if ( $class->_fieldIsIndexed( $args, $selectField ) ) {
19 4         34 return $class->_query( $args, $selectField, $value,
20             { query => "$selectField=?", values => [$value] }, @fields );
21             }
22             else {
23 2         50 return $class->SUPER::searchOn(@_);
24             }
25             }
26              
27             sub searchOnExpr {
28 2     2 0 5 my $class = shift;
29 2         6 my ( $args, $selectField, $value, @fields ) = @_;
30              
31             # Escape quotes
32 2         6 $value =~ s/'/''/g;
33 2         5 $selectField =~ s/'/''/g;
34 2 100       8 if ( $class->_fieldIsIndexed( $args, $selectField ) ) {
35 1         4 $value =~ s/\*/%/g;
36 1         10 return $class->_query( $args, $selectField, $value,
37             { query => "$selectField like ?", values => [$value] }, @fields );
38             }
39             else {
40 1         11 return $class->SUPER::searchOnExpr(@_);
41             }
42             }
43              
44             sub _query {
45 5     5   18 my ( $class, $args, $selectField, $value, $query, @fields ) = @_;
46 5         12 my %res = ();
47             my $index =
48             ref( $args->{Index} )
49             ? $args->{Index}
50 5 50       32 : [ split /\s+/, $args->{Index} ];
51              
52 5         16 my $dbh = $class->_classDbh($args);
53             my $table_name = $args->{TableName}
54 5   33     26 || $Apache::Session::Store::DBI::TableName;
55              
56             # Case 1: all requested fields are also indexed
57 5         28 my $indexed = $class->_tabInTab( \@fields, $index );
58 5         10 my $sth;
59 5 100       13 if ($indexed) {
60 1         3 my $fields = join( ',', 'id', map { s/'//g; $_ } @fields );
  2         7  
  2         7  
61 1         11 $sth = $dbh->prepare(
62             "SELECT $fields from $table_name where $query->{query}");
63 1         87 $sth->execute( @{ $query->{values} } );
  1         64  
64 1         63 return $sth->fetchall_hashref('id');
65             }
66              
67             # Case 1: at least one field isn't indexed, decoding is needed
68             else {
69 4         27 $sth =
70             $dbh->prepare(
71             "SELECT id,a_session from $table_name where $query->{query}");
72 4         335 $sth->execute( @{ $query->{values} } );
  4         261  
73 4         81 while ( my @row = $sth->fetchrow_array ) {
74 4     4   35 no strict 'refs';
  4         11  
  4         3815  
75 7         465 my $self = eval "&${class}::populate();";
76 7         31 my $sub = $self->{unserialize};
77 7         14 eval {
78 7         28 my $tmp = &$sub( { serialized => $row[1] } );
79 7 100       24 if (@fields) {
80 2         16 $res{ $row[0] }->{$_} = $tmp->{$_} foreach (@fields);
81             }
82             else {
83 5         56 $res{ $row[0] } = $tmp;
84             }
85             };
86 7 50       38 if ($@) {
87 0         0 print STDERR "Error in session $row[0]: $@\n";
88 0         0 delete $res{ $row[0] };
89             }
90             }
91             }
92 4         106 return \%res;
93             }
94              
95             sub deleteIfLowerThan {
96 0     0 0 0 my ( $class, $args, $rule ) = @_;
97 0         0 my ( $query, %fields );
98             my $index =
99             ref( $args->{Index} )
100             ? $args->{Index}
101 0 0       0 : [ split /\s+/, $args->{Index} ];
102 0 0       0 if ( $rule->{or} ) {
    0          
103             $query = join ' OR ', map {
104 0         0 $fields{$_}++;
105 0         0 $class->_buildLowerThanExpression( $_, $rule->{or}->{$_} )
106             }
107 0         0 keys %{ $rule->{or} };
  0         0  
108             }
109             elsif ( $rule->{and} ) {
110             $query = join ' AND ', map {
111 0         0 $fields{$_}++;
112 0         0 $class->_buildLowerThanExpression( $_, $rule->{or}->{$_} )
113             }
114 0         0 keys %{ $rule->{or} };
  0         0  
115             }
116 0 0       0 if ( $rule->{not} ) {
117             $query = "($query) AND "
118             . join( ' AND ',
119 0         0 map { $fields{$_}++; "$_ <> '$rule->{not}->{$_}'" }
  0         0  
120 0         0 keys %{ $rule->{not} } );
  0         0  
121             }
122 0 0 0     0 return 0
123             unless ( $query and $class->_tabInTab( [ keys %fields ], $index ) );
124 0         0 my $dbh = $class->_classDbh($args);
125             my $table_name = $args->{TableName}
126 0   0     0 || $Apache::Session::Store::DBI::TableName;
127 0         0 my $rows = $dbh->do("DELETE FROM $table_name WHERE $query");
128 0 0       0 return 0 unless defined $rows;
129              
130 0 0       0 if (wantarray) {
131 0 0       0 $rows = 0 if $rows == -1;
132 0         0 return ( 1, $rows );
133             }
134             else {
135 0         0 return 1;
136             }
137             }
138              
139             # Let specialized modules override this syntax if they need to
140             sub _buildLowerThanExpression {
141 0     0   0 my ( $class, $field, $value ) = @_;
142 0         0 return "cast($field as integer) < $value";
143             }
144              
145             sub get_key_from_all_sessions {
146 6     6 0 1633 my $class = shift;
147 6         11 my $args = shift;
148 6         12 my $data = shift;
149              
150             my $table_name = $args->{TableName}
151 6   33     62 || $Apache::Session::Store::DBI::TableName;
152 6         22 my $dbh = $class->_classDbh($args);
153              
154             # Special case if all wanted fields are indexed
155 6 100 100     33 if ( $data and ref($data) ne 'CODE' ) {
156 2 50       8 $data = [$data] unless ( ref($data) );
157             my $index =
158             ref( $args->{Index} )
159             ? $args->{Index}
160 2 50       15 : [ split /\s+/, $args->{Index} ];
161              
162             # Test if one field isn't indexed
163 2         12 my $indexed = $class->_tabInTab( $data, $index );
164              
165             # OK, all fields are indexed
166 2 100       7 if ($indexed) {
167             my $sth =
168             $dbh->prepare_cached( 'SELECT id,'
169 1         3 . join( ',', map { s/'/''/g; $_ } @$data )
  2         6  
  2         12  
170             . " from $table_name" );
171 1         144 $sth->execute;
172 1         20 return $sth->fetchall_hashref('id');
173             }
174             }
175 5         32 my $sth = $dbh->prepare_cached("SELECT id,a_session from $table_name");
176 5         721 $sth->execute;
177 5         17 my %res;
178             my $next = (
179             $args->{DataSource} =~ /^sybase/i
180             ? sub {
181 0     0   0 require Storable;
182 0         0 return Storable::thaw( pack( 'H*', $_[0] ) );
183             }
184             : $args->{DataSource} =~ /^mysql/i ? sub {
185 0     0   0 require MIME::Base64;
186 0         0 require Storable;
187 0         0 return Storable::thaw( MIME::Base64::decode_base64( $_[0] ) );
188             }
189             : undef
190 5 50       35 );
    50          
191 5         54 while ( my @row = $sth->fetchrow_array ) {
192 4     4   34 no strict 'refs';
  4         9  
  4         1622  
193 140         7075 my $self = eval "&${class}::populate();";
194 140         425 eval {
195 140         229 my $sub = $self->{unserialize};
196 140         430 my $tmp = &$sub( { serialized => $row[1] }, $next );
197 140 100       411 if ( ref($data) eq 'CODE' ) {
    100          
198 84         2449 $tmp = &$data( $tmp, $row[0] );
199 84 50       222 $res{ $row[0] } = $tmp if ( defined($tmp) );
200             }
201             elsif ($data) {
202 28 50       96 $data = [$data] unless ( ref($data) );
203 28         189 $res{ $row[0] }->{$_} = $tmp->{$_} foreach (@$data);
204             }
205             else {
206 28         103 $res{ $row[0] } = $tmp;
207             }
208             };
209 140 50       542 if ($@) {
210 0         0 print STDERR "Error in session $row[0]: $@\n";
211 0         0 delete $res{ $row[0] };
212             }
213             }
214 5         97 return \%res;
215             }
216              
217             sub _classDbh {
218 11     11   28 my $class = shift;
219 11         26 my $args = shift;
220              
221 11 50       32 my $datasource = $args->{DataSource} or die "No datasource given !";
222 11         20 my $username = $args->{UserName};
223 11         17 my $password = $args->{Password};
224 11   50     50 my $dbh =
225             DBI->connect_cached( $datasource, $username, $password,
226             { RaiseError => 1, AutoCommit => 1 } )
227             || die $DBI::errstr;
228 11 50       3106 if ( $datasource =~ /^dbi:sqlite/i ) {
    0          
    0          
229 11         57 $dbh->{sqlite_unicode} = 1;
230             }
231             elsif ( $datasource =~ /^dbi:mysql/i ) {
232 0         0 $dbh->{mysql_enable_utf8} = 1;
233             }
234             elsif ( $datasource =~ /^dbi:pg/i ) {
235 0         0 $dbh->{pg_enable_utf8} = 1;
236             }
237 11         34 return $dbh;
238             }
239              
240             1;
241