File | /project/perl/lib/DBIx/ContextualFetch.pm |
Statements Executed | 1124 |
Statement Execution Time | 304ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
462 | 1 | 1 | 13.7ms | 17.9ms | fetch | DBIx::ContextualFetch::st::
12 | 1 | 1 | 1.84ms | 282ms | _untaint_execute | DBIx::ContextualFetch::st::
12 | 6 | 3 | 938µs | 283ms | execute | DBIx::ContextualFetch::st::
12 | 1 | 1 | 378µs | 378µs | _disallow_references | DBIx::ContextualFetch::st::
1 | 1 | 1 | 173µs | 1.96ms | select_row | DBIx::ContextualFetch::st::
0 | 0 | 0 | 0s | 0s | BEGIN | DBIx::ContextualFetch::
0 | 0 | 0 | 0s | 0s | BEGIN | DBIx::ContextualFetch::db::
0 | 0 | 0 | 0s | 0s | BEGIN | DBIx::ContextualFetch::st::
0 | 0 | 0 | 0s | 0s | fetch_hash | DBIx::ContextualFetch::st::
0 | 0 | 0 | 0s | 0s | fetchall | DBIx::ContextualFetch::st::
0 | 0 | 0 | 0s | 0s | fetchall_hash | DBIx::ContextualFetch::st::
0 | 0 | 0 | 0s | 0s | select_col | DBIx::ContextualFetch::st::
0 | 0 | 0 | 0s | 0s | select_val | DBIx::ContextualFetch::st::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package DBIx::ContextualFetch; | ||||
2 | |||||
3 | 1 | 6µs | $VERSION = '1.03'; | ||
4 | |||||
5 | 3 | 90µs | 1 | 27µs | use strict; # spent 27µs making 1 call to strict::import |
6 | 3 | 87µs | 1 | 120µs | use warnings; # spent 120µs making 1 call to warnings::import |
7 | 3 | 106µs | 1 | 92µs | no warnings 'uninitialized'; # spent 92µs making 1 call to warnings::unimport |
8 | |||||
9 | 3 | 103µs | 1 | 256µs | use base 'DBI'; # spent 256µs making 1 call to base::import |
10 | |||||
11 | package DBIx::ContextualFetch::db; | ||||
12 | 3 | 120µs | 1 | 3.74ms | use base 'DBI::db'; # spent 3.74ms making 1 call to base::import |
13 | |||||
14 | package DBIx::ContextualFetch::st; | ||||
15 | 3 | 1.17ms | 1 | 538µs | use base 'DBI::st'; # spent 538µs making 1 call to base::import |
16 | |||||
17 | # spent 283ms (938µs+283) within DBIx::ContextualFetch::st::execute which was called 12 times, avg 23.6ms/call:
# 4 times (291µs+19.8ms) by Class::DBI::Pg::pg_version at line 92 of Class/DBI/Pg.pm, avg 5.02ms/call
# 2 times (149µs+157ms) by Class::DBI::Pg::set_up_table at line 25 of Class/DBI/Pg.pm, avg 78.7ms/call
# 2 times (184µs+44.0ms) by Class::DBI::Pg::set_up_table at line 37 of Class/DBI/Pg.pm, avg 22.1ms/call
# 2 times (168µs+3.82ms) by Class::DBI::Pg::set_up_table at line 48 of Class/DBI/Pg.pm, avg 1.99ms/call
# once (73µs+56.2ms) by Class::DBI::sth_to_objects at line 1139 of Class/DBI.pm
# once (73µs+1.59ms) by DBIx::ContextualFetch::st::select_row at line 87 | ||||
18 | 48 | 484µs | my ($sth) = shift; | ||
19 | |||||
20 | my $rv; | ||||
21 | |||||
22 | # Allow $sth->execute(\@param, \@cols) and | ||||
23 | # $sth->execute(undef, \@cols) syntax. | ||||
24 | 24 | 397µs | if ( @_ == 2 | ||
25 | and (!defined $_[0] || ref $_[0] eq 'ARRAY') | ||||
26 | and ref $_[1] eq 'ARRAY') { | ||||
27 | my ($bind_params, $bind_cols) = @_; | ||||
28 | $rv = $sth->_untaint_execute(@$bind_params); | ||||
29 | $sth->SUPER::bind_columns(@$bind_cols); | ||||
30 | } else { | ||||
31 | $sth->_disallow_references(@_); # spent 378µs making 12 calls to DBIx::ContextualFetch::st::_disallow_references, avg 32µs/call | ||||
32 | $rv = $sth->_untaint_execute(@_); # spent 282ms making 12 calls to DBIx::ContextualFetch::st::_untaint_execute, avg 23.5ms/call | ||||
33 | } | ||||
34 | return $rv; | ||||
35 | } | ||||
36 | |||||
37 | # spent 378µs within DBIx::ContextualFetch::st::_disallow_references which was called 12 times, avg 32µs/call:
# 12 times (378µs+0s) by DBIx::ContextualFetch::st::execute at line 31, avg 32µs/call | ||||
38 | 24 | 329µs | my $self = shift; | ||
39 | foreach (@_) { | ||||
40 | 7 | 109µs | next unless ref $_; | ||
41 | next if overload::Method($_, q{""}); | ||||
42 | next if overload::Method($_, q{0+}); | ||||
43 | die "Cannot call execute with a reference ($_)\n"; | ||||
44 | } | ||||
45 | } | ||||
46 | |||||
47 | # local $sth->{Taint} leaks in old perls :( | ||||
48 | # spent 282ms (1.84+280) within DBIx::ContextualFetch::st::_untaint_execute which was called 12 times, avg 23.5ms/call:
# 12 times (1.84ms+280ms) by DBIx::ContextualFetch::st::execute at line 32, avg 23.5ms/call | ||||
49 | 72 | 282ms | my $sth = shift; | ||
50 | my $old_value = $sth->{Taint}; # spent 171µs making 12 calls to DBI::common::FETCH, avg 14µs/call | ||||
51 | $sth->{Taint} = 0; # spent 156µs making 12 calls to DBI::common::STORE, avg 13µs/call | ||||
52 | my $ret = $sth->SUPER::execute(@_); # spent 280ms making 12 calls to DBI::st::execute, avg 23.3ms/call | ||||
53 | $sth->{Taint} = $old_value; # spent 184µs making 12 calls to DBI::common::STORE, avg 15µs/call | ||||
54 | return $ret; | ||||
55 | } | ||||
56 | |||||
57 | # spent 17.9ms (13.7+4.20) within DBIx::ContextualFetch::st::fetch which was called 462 times, avg 39µs/call:
# 462 times (13.7ms+4.20ms) by Class::DBI::sth_to_objects at line 1141 of Class/DBI.pm, avg 39µs/call | ||||
58 | 924 | 18.1ms | my ($sth) = shift; | ||
59 | return wantarray | ||||
60 | ? $sth->SUPER::fetchrow_array # spent 4.20ms making 462 calls to DBI::st::fetchrow_arrayref, avg 9µs/call | ||||
61 | : $sth->SUPER::fetchrow_arrayref; | ||||
62 | } | ||||
63 | |||||
64 | sub fetch_hash { | ||||
65 | my ($sth) = shift; | ||||
66 | my $row = $sth->SUPER::fetchrow_hashref; | ||||
67 | return unless defined $row; | ||||
68 | return wantarray ? %$row : $row; | ||||
69 | } | ||||
70 | |||||
71 | sub fetchall { | ||||
72 | my ($sth) = shift; | ||||
73 | my $rows = $sth->SUPER::fetchall_arrayref; | ||||
74 | return wantarray ? @$rows : $rows; | ||||
75 | } | ||||
76 | |||||
77 | # There may be some code in DBI->fetchall_arrayref, but its undocumented. | ||||
78 | sub fetchall_hash { | ||||
79 | my ($sth) = shift; | ||||
80 | my (@rows, $row); | ||||
81 | push @rows, $row while ($row = $sth->SUPER::fetchrow_hashref); | ||||
82 | return wantarray ? @rows : \@rows; | ||||
83 | } | ||||
84 | |||||
85 | # spent 1.96ms (173µs+1.78) within DBIx::ContextualFetch::st::select_row which was called
# once (173µs+1.78ms) by Class::DBI::_flesh at line 857 of Class/DBI.pm | ||||
86 | 5 | 288µs | my ($sth, @args) = @_; | ||
87 | $sth->execute(@args); # spent 1.67ms making 1 call to DBIx::ContextualFetch::st::execute | ||||
88 | my @row = $sth->fetchrow_array; # spent 100µs making 1 call to DBI::st::fetchrow_array | ||||
89 | $sth->finish; # spent 16µs making 1 call to DBI::st::finish | ||||
90 | return @row; | ||||
91 | } | ||||
92 | |||||
93 | sub select_col { | ||||
94 | my ($sth, @args) = @_; | ||||
95 | my (@row, $cur); | ||||
96 | $sth->execute(@args); | ||||
97 | $sth->bind_col(1, \$cur); | ||||
98 | push @row, $cur while $sth->fetch; | ||||
99 | $sth->finish; | ||||
100 | return @row; | ||||
101 | } | ||||
102 | |||||
103 | sub select_val { | ||||
104 | my ($sth, @args) = @_; | ||||
105 | return ($sth->select_row(@args))[0]; | ||||
106 | } | ||||
107 | |||||
108 | 1 | 15µs | return 1; | ||
109 | |||||
110 | __END__ | ||||
111 | |||||
112 | =head1 NAME | ||||
113 | |||||
114 | DBIx::ContextualFetch - Add contextual fetches to DBI | ||||
115 | |||||
116 | =head1 SYNOPSIS | ||||
117 | |||||
118 | my $dbh = DBI->connect(...., { RootClass => "DBIx::ContextualFetch" }); | ||||
119 | |||||
120 | # Modified statement handle methods. | ||||
121 | my $rv = $sth->execute; | ||||
122 | my $rv = $sth->execute(@bind_values); | ||||
123 | my $rv = $sth->execute(\@bind_values, \@bind_cols); | ||||
124 | |||||
125 | # In addition to the normal DBI sth methods... | ||||
126 | my $row_ref = $sth->fetch; | ||||
127 | my @row = $sth->fetch; | ||||
128 | |||||
129 | my $row_ref = $sth->fetch_hash; | ||||
130 | my %row = $sth->fetch_hash; | ||||
131 | |||||
132 | my $rows_ref = $sth->fetchall; | ||||
133 | my @rows = $sth->fetchall; | ||||
134 | |||||
135 | my $rows_ref = $sth->fetchall_hash; | ||||
136 | my @tbl = $sth->fetchall_hash; | ||||
137 | |||||
138 | =head1 DESCRIPTION | ||||
139 | |||||
140 | It always struck me odd that DBI didn't take much advantage of Perl's | ||||
141 | context sensitivity. DBIx::ContextualFetch redefines some of the various | ||||
142 | fetch methods to fix this oversight. It also adds a few new methods for | ||||
143 | convenience (though not necessarily efficiency). | ||||
144 | |||||
145 | =head1 SET-UP | ||||
146 | |||||
147 | my $dbh = DBIx::ContextualFetch->connect(@info); | ||||
148 | my $dbh = DBI->connect(@info, { RootClass => "DBIx::ContextualFetch" }); | ||||
149 | |||||
150 | To use this method, you can either make sure that everywhere you normall | ||||
151 | call DBI->connect() you either call it on DBIx::ContextualFetch, or that | ||||
152 | you pass this as your RootClass. After this DBI will Do The Right Thing | ||||
153 | and pass all its calls through us. | ||||
154 | |||||
155 | =head1 EXTENSIONS | ||||
156 | |||||
157 | =head2 execute | ||||
158 | |||||
159 | $rv = $sth->execute; | ||||
160 | $rv = $sth->execute(@bind_values); | ||||
161 | $rv = $sth->execute(\@bind_values, \@bind_cols); | ||||
162 | |||||
163 | execute() is enhanced slightly: | ||||
164 | |||||
165 | If called with no arguments, or with a simple list, execute() operates | ||||
166 | normally. When when called with two array references, it performs | ||||
167 | the functions of bind_param, execute and bind_columns similar to the | ||||
168 | following: | ||||
169 | |||||
170 | $sth->execute(@bind_values); | ||||
171 | $sth->bind_columns(undef, @bind_cols); | ||||
172 | |||||
173 | In addition, execute will accept tainted @bind_values. I can't think of | ||||
174 | what a malicious user could do with a tainted bind value (in the general | ||||
175 | case. Your application may vary.) | ||||
176 | |||||
177 | Thus a typical idiom would be: | ||||
178 | |||||
179 | $sth->execute([$this, $that], [\($foo, $bar)]); | ||||
180 | |||||
181 | Of course, this method provides no way of passing bind attributes | ||||
182 | through to bind_param or bind_columns. If that is necessary, then you | ||||
183 | must perform the bind_param, execute, bind_col sequence yourself. | ||||
184 | |||||
185 | =head2 fetch | ||||
186 | |||||
187 | $row_ref = $sth->fetch; | ||||
188 | @row = $sth->fetch; | ||||
189 | |||||
190 | A context sensitive version of fetch(). When in scalar context, it will | ||||
191 | act as fetchrow_arrayref. In list context it will use fetchrow_array. | ||||
192 | |||||
193 | =head2 fetch_hash | ||||
194 | |||||
195 | $row_ref = $sth->fetch_hash; | ||||
196 | %row = $sth->fetch_hash; | ||||
197 | |||||
198 | A modification on fetchrow_hashref. When in scalar context, it acts just | ||||
199 | as fetchrow_hashref() does. In list context it returns the complete hash. | ||||
200 | |||||
201 | =head2 fetchall | ||||
202 | |||||
203 | $rows_ref = $sth->fetchall; | ||||
204 | @rows = $sth->fetchall; | ||||
205 | |||||
206 | A modification on fetchall_arrayref. In scalar context it acts as | ||||
207 | fetchall_arrayref. In list it returns an array of references to rows | ||||
208 | fetched. | ||||
209 | |||||
210 | =head2 fetchall_hash | ||||
211 | |||||
212 | $rows_ref = $sth->fetchall_hash; | ||||
213 | @rows = $sth->fetchall_hash; | ||||
214 | |||||
215 | A mating of fetchall_arrayref() with fetchrow_hashref(). It gets all rows | ||||
216 | from the hash, each as hash references. In scalar context it returns | ||||
217 | a reference to an array of hash references. In list context it returns | ||||
218 | a list of hash references. | ||||
219 | |||||
220 | =head1 ORIGINAL AUTHOR | ||||
221 | |||||
222 | Michael G Schwern as part of Ima::DBI | ||||
223 | |||||
224 | =head1 CURRENT MAINTAINER | ||||
225 | |||||
226 | Tony Bowden <tony@tmtm.com> | ||||
227 | |||||
228 | =head1 LICENSE | ||||
229 | |||||
230 | This library is free software; you can redistribute it and/or modify | ||||
231 | it under the same terms as Perl itself. | ||||
232 | |||||
233 | =head1 SEE ALSO | ||||
234 | |||||
235 | L<DBI>. L<Ima::DBI>. L<Class::DBI>. | ||||
236 |