File | /project/perl/lib/Ima/DBI.pm |
Statements Executed | 253 |
Statement Execution Time | 7.06ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
13 | 1 | 1 | 2.04ms | 3.67ms | set_sql | Ima::DBI::
8 | 3 | 2 | 392µs | 170ms | __ANON__[:316] | Ima::DBI::
13 | 1 | 1 | 380µs | 380µs | _mk_sql_closure | Ima::DBI::
2 | 2 | 2 | 245µs | 6.79ms | __ANON__[:384] | Ima::DBI::
1 | 1 | 1 | 229µs | 726µs | set_db | Ima::DBI::
27 | 3 | 2 | 180µs | 180µs | CORE:subst (opcode) | Ima::DBI::
1 | 1 | 1 | 86µs | 255µs | _remember_handle | Ima::DBI::
1 | 1 | 1 | 77µs | 197µs | _add_default_attributes | Ima::DBI::
2 | 1 | 1 | 51µs | 51µs | transform_sql | Ima::DBI::
1 | 1 | 1 | 37µs | 37µs | _mk_db_closure | Ima::DBI::
1 | 1 | 1 | 16µs | 16µs | _default_attributes | Ima::DBI::
0 | 0 | 0 | 0s | 0s | BEGIN | Ima::DBI::
0 | 0 | 0 | 0s | 0s | DBIwarn | Ima::DBI::
0 | 0 | 0 | 0s | 0s | _croak | Ima::DBI::
0 | 0 | 0 | 0s | 0s | commit | Ima::DBI::
0 | 0 | 0 | 0s | 0s | db_handles | Ima::DBI::
0 | 0 | 0 | 0s | 0s | db_names | Ima::DBI::
0 | 0 | 0 | 0s | 0s | rollback | Ima::DBI::
0 | 0 | 0 | 0s | 0s | sql_names | Ima::DBI::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package Ima::DBI; | ||||
2 | |||||
3 | 1 | 6µs | $VERSION = '0.34'; | ||
4 | |||||
5 | 3 | 103µs | 1 | 26µs | use strict; # spent 26µs making 1 call to strict::import |
6 | 3 | 89µs | 1 | 0s | use base 'Class::Data::Inheritable'; # spent 271µs making 1 call to base::import, recursion: max depth 4, time 271µs |
7 | 3 | 955µs | 1 | 143µs | use DBI; # spent 143µs making 1 call to Exporter::import |
8 | |||||
9 | # Some class data to store a per-class list of handles. | ||||
10 | 1 | 37µs | 1 | 68µs | Ima::DBI->mk_classdata('__Database_Names'); # spent 68µs making 1 call to Class::Data::Inheritable::mk_classdata |
11 | 1 | 22µs | 1 | 49µs | Ima::DBI->mk_classdata('__Statement_Names'); # spent 49µs making 1 call to Class::Data::Inheritable::mk_classdata |
12 | |||||
13 | =head1 NAME | ||||
14 | |||||
15 | Ima::DBI - Database connection caching and organization | ||||
16 | |||||
17 | =head1 SYNOPSIS | ||||
18 | |||||
19 | package Foo; | ||||
20 | use base 'Ima::DBI'; | ||||
21 | |||||
22 | # Class-wide methods. | ||||
23 | Foo->set_db($db_name, $data_source, $user, $password); | ||||
24 | Foo->set_db($db_name, $data_source, $user, $password, \%attr); | ||||
25 | |||||
26 | my @database_names = Foo->db_names; | ||||
27 | my @database_handles = Foo->db_handles; | ||||
28 | |||||
29 | Foo->set_sql($sql_name, $statement, $db_name); | ||||
30 | Foo->set_sql($sql_name, $statement, $db_name, $cache); | ||||
31 | |||||
32 | my @statement_names = Foo->sql_names; | ||||
33 | |||||
34 | # Object methods. | ||||
35 | $dbh = $obj->db_*; # Where * is the name of the db connection. | ||||
36 | $sth = $obj->sql_*; # Where * is the name of the sql statement. | ||||
37 | $sth = $obj->sql_*(@sql_pieces); | ||||
38 | |||||
39 | $obj->DBIwarn($what, $doing); | ||||
40 | |||||
41 | my $rc = $obj->commit; | ||||
42 | my $rc = $obj->commit(@db_names); | ||||
43 | |||||
44 | my $rc = $obj->rollback; | ||||
45 | my $rc = $obj->rollback(@db_names); | ||||
46 | |||||
47 | |||||
48 | =head1 DESCRIPTION | ||||
49 | |||||
50 | Ima::DBI attempts to organize and facilitate caching and more efficient | ||||
51 | use of database connections and statement handles by storing DBI and | ||||
52 | SQL information with your class (instead of as seperate objects). | ||||
53 | This allows you to pass around just one object without worrying about | ||||
54 | a trail of DBI handles behind it. | ||||
55 | |||||
56 | One of the things I always found annoying about writing large programs | ||||
57 | with DBI was making sure that I didn't have duplicate database handles | ||||
58 | open. I was also annoyed by the somewhat wasteful nature of the | ||||
59 | prepare/execute/finish route I'd tend to go through in my subroutines. | ||||
60 | The new DBI->connect_cached and DBI->prepare_cached helped a lot, but | ||||
61 | I still had to throw around global datasource, username and password | ||||
62 | information. | ||||
63 | |||||
64 | So, after a while I grew a small library of DBI helper routines and | ||||
65 | techniques. Ima::DBI is the culmination of all this, put into a nice(?), | ||||
66 | clean(?) class to be inherited from. | ||||
67 | |||||
68 | =head2 Why should I use this thing? | ||||
69 | |||||
70 | Ima::DBI is a little odd, and it's kinda hard to explain. So lemme | ||||
71 | explain why you'd want to use this thing... | ||||
72 | |||||
73 | =over 4 | ||||
74 | |||||
75 | =item * Consolidation of all SQL statements and database information | ||||
76 | |||||
77 | No matter what, embedding one language into another is messy. | ||||
78 | DBI alleviates this somewhat, but I've found a tendency to have that | ||||
79 | scatter the SQL around inside the Perl code. Ima::DBI allows you to | ||||
80 | easily group the SQL statements in one place where they are easier to | ||||
81 | maintain (especially if one developer is writing the SQL, another writing | ||||
82 | the Perl). Alternatively, you can place your SQL statement alongside | ||||
83 | the code which uses it. Whatever floats your boat. | ||||
84 | |||||
85 | Database connection information (data source, username, password, | ||||
86 | atrributes, etc...) can also be consolidated together and tracked. | ||||
87 | |||||
88 | Both the SQL and the connection info are probably going to change a lot, | ||||
89 | so having them well organized and easy to find in the code is a Big Help. | ||||
90 | |||||
91 | =item * Holds off opening a database connection until necessary. | ||||
92 | |||||
93 | While Ima::DBI is informed of all your database connections and SQL | ||||
94 | statements at compile-time, it will not connect to the database until | ||||
95 | you actually prepare a statement on that connection. | ||||
96 | |||||
97 | This is obviously very good for programs that sometimes never touch | ||||
98 | the database. It's also good for code that has lots of possible | ||||
99 | connections and statements, but which typically only use a few. | ||||
100 | Kinda like an autoloader. | ||||
101 | |||||
102 | =item * Easy integration of the DBI handles into your class | ||||
103 | |||||
104 | Ima::DBI causes each database handle to be associated with your class, | ||||
105 | allowing you to pull handles from an instance of your object, as well | ||||
106 | as making many oft-used DBI methods available directly from your | ||||
107 | instance. | ||||
108 | |||||
109 | This gives you a cleaner OO design, since you can now just throw | ||||
110 | around the object as usual and it will carry its associated DBI | ||||
111 | baggage with it. | ||||
112 | |||||
113 | =item * Honors taint mode | ||||
114 | |||||
115 | It always struck me as a design deficiency that tainted SQL statements | ||||
116 | could be passed to $sth->prepare(). For example: | ||||
117 | |||||
118 | # $user is from an untrusted source and is tainted. | ||||
119 | $user = get_user_data_from_the_outside_world; | ||||
120 | $sth = $dbh->prepare('DELETE FROM Users WHERE User = $user'); | ||||
121 | |||||
122 | Looks innocent enough... but what if $user was the string "1 OR User LIKE | ||||
123 | '%'". You just blew away all your users. Hope you have backups. | ||||
124 | |||||
125 | Ima::DBI turns on the DBI->connect Taint attribute so that all DBI | ||||
126 | methods (except execute()) will no longer accept tainted data. | ||||
127 | See L<DBI/Taint> for details. | ||||
128 | |||||
129 | =item * Taints returned data | ||||
130 | |||||
131 | Databases should be like any other system call. It's the scary Outside | ||||
132 | World, thus it should be tainted. Simple. Ima::DBI turns on DBI's Taint | ||||
133 | attribute on each connection. This feature is overridable by passing | ||||
134 | your own Taint attribute to set_db as normal for DBI. See L<DBI/Taint> | ||||
135 | for details. | ||||
136 | |||||
137 | =item * Encapsulation of some of the more repetitive bits of everyday DBI usage | ||||
138 | |||||
139 | I get lazy a lot and I forget to do things I really should, like using | ||||
140 | bind_cols(), or rigorous error checking. Ima::DBI does some of this | ||||
141 | stuff automatically, other times it just makes it more convenient. | ||||
142 | |||||
143 | =item * Encapsulation of DBI's cache system | ||||
144 | |||||
145 | DBI's automatic handle caching system is relatively new, and some people | ||||
146 | aren't aware of its use. Ima::DBI uses it automatically, so you don't | ||||
147 | have to worry about it. (It even makes it a bit more efficient) | ||||
148 | |||||
149 | =item * Sharing of database and sql information amongst inherited classes | ||||
150 | |||||
151 | Any SQL statements and connections created by a class are available to | ||||
152 | its children via normal method inheritance. | ||||
153 | |||||
154 | =item * Guarantees one connection per program. | ||||
155 | |||||
156 | One program, one database connection (per database user). One program, | ||||
157 | one prepared statement handle (per statement, per database user). | ||||
158 | That's what Ima::DBI enforces. Extremely handy in persistant environments | ||||
159 | (servers, daemons, mod_perl, FastCGI, etc...) | ||||
160 | |||||
161 | =item * Encourages use of bind parameters and columns | ||||
162 | |||||
163 | Bind parameters are safer and more efficient than embedding the column | ||||
164 | information straight into the SQL statement. Bind columns are more | ||||
165 | efficient than normal fetching. Ima::DBI pretty much requires the usage | ||||
166 | of the former, and eases the use of the latter. | ||||
167 | |||||
168 | =back | ||||
169 | |||||
170 | =head2 Why shouldn't I use this thing. | ||||
171 | |||||
172 | =over 4 | ||||
173 | |||||
174 | =item * It's all about OO | ||||
175 | |||||
176 | Although it is possible to use Ima::DBI as a stand-alone module as | ||||
177 | part of a function-oriented design, its generally not to be used | ||||
178 | unless integrated into an object-oriented design. | ||||
179 | |||||
180 | =item * Overkill for small programs | ||||
181 | |||||
182 | =item * Overkill for programs with only one or two SQL statements | ||||
183 | |||||
184 | Its up to you whether the trouble of setting up a class and jumping | ||||
185 | through the necessary Ima::DBI hoops is worth it for small programs. | ||||
186 | To me, it takes just as much time to set up an Ima::DBI subclass as it | ||||
187 | would to access DBI without it... but then again I wrote the module. | ||||
188 | YMMV. | ||||
189 | |||||
190 | =item * Overkill for programs that only use their SQL statements once | ||||
191 | |||||
192 | Ima::DBI's caching might prove to be an unecessary performance hog if | ||||
193 | you never use the same SQL statement twice. Not sure, I haven't | ||||
194 | looked into it. | ||||
195 | |||||
196 | =back | ||||
197 | |||||
198 | |||||
199 | =head1 USAGE | ||||
200 | |||||
201 | The basic steps to "DBIing" a class are: | ||||
202 | |||||
203 | =over 4 | ||||
204 | |||||
205 | =item 1 | ||||
206 | |||||
207 | Inherit from Ima::DBI | ||||
208 | |||||
209 | =item 2 | ||||
210 | |||||
211 | Set up and name all your database connections via set_db() | ||||
212 | |||||
213 | =item 3 | ||||
214 | |||||
215 | Set up and name all your SQL statements via set_sql() | ||||
216 | |||||
217 | =item 4 | ||||
218 | |||||
219 | Use sql_* to retrieve your statement handles ($sth) as needed and db_* | ||||
220 | to retreive database handles ($dbh). | ||||
221 | |||||
222 | |||||
223 | =back | ||||
224 | |||||
225 | Have a look at L<EXAMPLE> below. | ||||
226 | |||||
227 | =head1 TAINTING | ||||
228 | |||||
229 | Ima::DBI, by default, uses DBI's Taint flag on all connections. | ||||
230 | |||||
231 | This means that Ima::DBI methods do not accept tainted data, and that all | ||||
232 | data fetched from the database will be tainted. This may be different | ||||
233 | from the DBI behavior you're used to. See L<DBI/Taint> for details. | ||||
234 | |||||
235 | =head1 Class Methods | ||||
236 | |||||
237 | =head2 set_db | ||||
238 | |||||
239 | Foo->set_db($db_name, $data_source, $user, $password); | ||||
240 | Foo->set_db($db_name, $data_source, $user, $password, \%attr); | ||||
241 | |||||
242 | This method is used in place of DBI->connect to create your database | ||||
243 | handles. It sets up a new DBI database handle associated to $db_name. | ||||
244 | All other arguments are passed through to DBI->connect_cached. | ||||
245 | |||||
246 | A new method is created for each db you setup. This new method is called | ||||
247 | "db_$db_name"... so, for example, Foo->set_db("foo", ...) will create | ||||
248 | a method called "db_foo()". (Spaces in $db_name will be translated into | ||||
249 | underscores: '_') | ||||
250 | |||||
251 | %attr is combined with a set of defaults (RaiseError => 1, AutoCommit | ||||
252 | => 0, PrintError => 0, Taint => 1). This is a better default IMHO, | ||||
253 | however it does give databases without transactions (such as MySQL) a | ||||
254 | hard time. Be sure to turn AutoCommit back on if your database does | ||||
255 | not support transactions. | ||||
256 | |||||
257 | The actual database handle creation (and thus the database connection) | ||||
258 | is held off until a prepare is attempted with this handle. | ||||
259 | |||||
260 | =cut | ||||
261 | |||||
262 | sub _croak { my $self = shift; require Carp; Carp::croak(@_) } | ||||
263 | |||||
264 | # spent 726µs (229+497) within Ima::DBI::set_db which was called
# once (229µs+497µs) by Class::DBI::set_db at line 212 of Class/DBI.pm | ||||
265 | 1 | 6µs | my $class = shift; | ||
266 | 1 | 6µs | my $db_name = shift or $class->_croak("Need a db name"); | ||
267 | 1 | 26µs | 1 | 8µs | $db_name =~ s/\s/_/g; # spent 8µs making 1 call to Ima::DBI::CORE:subst |
268 | |||||
269 | 1 | 6µs | my $data_source = shift or $class->_croak("Need a data source"); | ||
270 | 1 | 5µs | my $user = shift || ""; | ||
271 | 1 | 6µs | my $password = shift || ""; | ||
272 | 1 | 6µs | my $attr = shift || {}; | ||
273 | 1 | 7µs | ref $attr eq 'HASH' or $class->_croak("$attr must be a hash reference"); | ||
274 | 1 | 48µs | 1 | 197µs | $attr = $class->_add_default_attributes($attr); # spent 197µs making 1 call to Ima::DBI::_add_default_attributes |
275 | |||||
276 | 1 | 44µs | 1 | 255µs | $class->_remember_handle($db_name); # spent 255µs making 1 call to Ima::DBI::_remember_handle |
277 | 3 | 739µs | 1 | 102µs | no strict 'refs'; # spent 102µs making 1 call to strict::unimport |
278 | 1 | 49µs | 1 | 37µs | *{ $class . "::db_$db_name" } = # spent 37µs making 1 call to Ima::DBI::_mk_db_closure |
279 | $class->_mk_db_closure($data_source, $user, $password, $attr); | ||||
280 | |||||
281 | 1 | 17µs | return 1; | ||
282 | } | ||||
283 | |||||
284 | # spent 197µs (77+120) within Ima::DBI::_add_default_attributes which was called
# once (77µs+120µs) by Ima::DBI::set_db at line 274 | ||||
285 | 1 | 6µs | my ($class, $user_attr) = @_; | ||
286 | 1 | 39µs | 1 | 120µs | my %attr = $class->_default_attributes; # spent 120µs making 1 call to Class::DBI::_default_attributes |
287 | 1 | 12µs | @attr{ keys %$user_attr } = values %$user_attr; | ||
288 | 1 | 21µs | return \%attr; | ||
289 | } | ||||
290 | |||||
291 | # spent 16µs within Ima::DBI::_default_attributes which was called
# once (16µs+0s) by Class::DBI::_default_attributes at line 201 of Class/DBI.pm | ||||
292 | ( | ||||
293 | 1 | 24µs | RaiseError => 1, | ||
294 | AutoCommit => 0, | ||||
295 | PrintError => 0, | ||||
296 | Taint => 1, | ||||
297 | RootClass => "DBIx::ContextualFetch" | ||||
298 | ); | ||||
299 | } | ||||
300 | |||||
301 | # spent 255µs (86+169) within Ima::DBI::_remember_handle which was called
# once (86µs+169µs) by Ima::DBI::set_db at line 276 | ||||
302 | 1 | 6µs | my ($class, $db) = @_; | ||
303 | 1 | 41µs | 1 | 27µs | my $handles = $class->__Database_Names || []; # spent 27µs making 1 call to Class::Data::Inheritable::__ANON__[Class/Data/Inheritable.pm:23] |
304 | 1 | 5µs | push @$handles, $db; | ||
305 | 1 | 26µs | 1 | 142µs | $class->__Database_Names($handles); # spent 142µs making 1 call to Class::Data::Inheritable::__ANON__[Class/Data/Inheritable.pm:23] |
306 | } | ||||
307 | |||||
308 | # spent 37µs within Ima::DBI::_mk_db_closure which was called
# once (37µs+0s) by Ima::DBI::set_db at line 278 | ||||
309 | 1 | 12µs | my ($class, @connection) = @_; | ||
310 | 1 | 4µs | my $dbh; | ||
311 | # spent 170ms (392µs+169) within Ima::DBI::__ANON__[/project/perl/lib/Ima/DBI.pm:316] which was called 8 times, avg 21.2ms/call:
# 4 times (179µs+30.4ms) by Class::DBI::Pg::pg_version at line 90 of Class/DBI/Pg.pm, avg 7.64ms/call
# 2 times (103µs+138ms) by Class::DBI::Pg::set_up_table at line 12 of Class/DBI/Pg.pm, avg 69.2ms/call
# 2 times (110µs+734µs) by Ima::DBI::__ANON__[/project/perl/lib/Ima/DBI.pm:384] at line 376, avg 422µs/call | ||||
312 | 8 | 529µs | 15 | 169ms | unless ($dbh && $dbh->FETCH('Active') && $dbh->ping) { # spent 138ms making 1 call to DBI::connect_cached
# spent 31.4ms making 7 calls to DBI::db::ping, avg 4.49ms/call
# spent 112µs making 7 calls to DBI::common::FETCH, avg 16µs/call |
313 | $dbh = DBI->connect_cached(@connection); | ||||
314 | } | ||||
315 | 8 | 127µs | return $dbh; | ||
316 | 1 | 26µs | }; | ||
317 | } | ||||
318 | |||||
319 | =head2 set_sql | ||||
320 | |||||
321 | Foo->set_sql($sql_name, $statement, $db_name); | ||||
322 | Foo->set_sql($sql_name, $statement, $db_name, $cache); | ||||
323 | |||||
324 | This method is used in place of DBI->prepare to create your statement | ||||
325 | handles. It sets up a new statement handle associated to $sql_name using | ||||
326 | the database connection associated with $db_name. $statement is passed | ||||
327 | through to either DBI->prepare or DBI->prepare_cached (depending on | ||||
328 | $cache) to create the statement handle. | ||||
329 | |||||
330 | If $cache is true or isn't given, then prepare_cached() will be used to | ||||
331 | prepare the statement handle and it will be cached. If $cache is false | ||||
332 | then a normal prepare() will be used and the statement handle will be | ||||
333 | recompiled on every sql_*() call. If you have a statement which changes | ||||
334 | a lot or is used very infrequently you might not want it cached. | ||||
335 | |||||
336 | A new method is created for each statement you set up. This new method | ||||
337 | is "sql_$sql_name"... so, as with set_db(), Foo->set_sql("bar", ..., | ||||
338 | "foo"); will create a method called "sql_bar()" which uses the database | ||||
339 | connection from "db_foo()". Again, spaces in $sql_name will be translated | ||||
340 | into underscores ('_'). | ||||
341 | |||||
342 | The actual statement handle creation is held off until sql_* is first | ||||
343 | called on this name. | ||||
344 | |||||
345 | =cut | ||||
346 | |||||
347 | # spent 3.67ms (2.04+1.63) within Ima::DBI::set_sql which was called 13 times, avg 283µs/call:
# 13 times (2.04ms+1.63ms) by Class::DBI::set_sql at line 933 of Class/DBI.pm, avg 283µs/call | ||||
348 | 13 | 81µs | my ($class, $sql_name, $statement, $db_name, $cache) = @_; | ||
349 | 13 | 87µs | $cache = 1 unless defined $cache; | ||
350 | |||||
351 | # ------------------------- sql_* closure ----------------------- # | ||||
352 | 13 | 61µs | my $db_meth = $db_name; | ||
353 | 13 | 311µs | 13 | 112µs | $db_meth =~ s/\s/_/g; # spent 112µs making 13 calls to Ima::DBI::CORE:subst, avg 9µs/call |
354 | 13 | 83µs | $db_meth = "db_$db_meth"; | ||
355 | |||||
356 | 13 | 216µs | 13 | 60µs | (my $sql_meth = $sql_name) =~ s/\s/_/g; # spent 60µs making 13 calls to Ima::DBI::CORE:subst, avg 5µs/call |
357 | 13 | 73µs | $sql_meth = "sql_$sql_meth"; | ||
358 | |||||
359 | # Remember the name of this handle for the class. | ||||
360 | 13 | 269µs | 13 | 369µs | my $handles = $class->__Statement_Names || []; # spent 369µs making 13 calls to Class::Data::Inheritable::__ANON__[Class/Data/Inheritable.pm:23], avg 28µs/call |
361 | 13 | 77µs | push @$handles, $sql_name; | ||
362 | 13 | 202µs | 13 | 710µs | $class->__Statement_Names($handles); # spent 710µs making 13 calls to Class::Data::Inheritable::__ANON__[Class/Data/Inheritable.pm:23], avg 55µs/call |
363 | |||||
364 | 3 | 994µs | 1 | 96µs | no strict 'refs'; # spent 96µs making 1 call to strict::unimport |
365 | 13 | 497µs | 13 | 380µs | *{ $class . "::$sql_meth" } = # spent 380µs making 13 calls to Ima::DBI::_mk_sql_closure, avg 29µs/call |
366 | $class->_mk_sql_closure($sql_name, $statement, $db_meth, $cache); | ||||
367 | |||||
368 | 13 | 187µs | return 1; | ||
369 | } | ||||
370 | |||||
371 | # spent 380µs within Ima::DBI::_mk_sql_closure which was called 13 times, avg 29µs/call:
# 13 times (380µs+0s) by Ima::DBI::set_sql at line 365, avg 29µs/call | ||||
372 | 13 | 96µs | my ($class, $sql_name, $statement, $db_meth, $cache) = @_; | ||
373 | |||||
374 | # spent 6.79ms (245µs+6.55) within Ima::DBI::__ANON__[/project/perl/lib/Ima/DBI.pm:384] which was called 2 times, avg 3.40ms/call:
# once (145µs+4.54ms) by Class::DBI::Plugin::RetrieveAll::__ANON__[/project/perl/lib/Class/DBI/Plugin/RetrieveAll.pm:77] at line 76 of Class/DBI/Plugin/RetrieveAll.pm
# once (100µs+2.01ms) by Class::DBI::_flesh at line 857 of Class/DBI.pm | ||||
375 | 2 | 12µs | my $class = shift; | ||
376 | 2 | 40µs | 2 | 844µs | my $dbh = $class->$db_meth(); # spent 844µs making 2 calls to Ima::DBI::__ANON__[Ima/DBI.pm:316], avg 422µs/call |
377 | |||||
378 | # Everything must pass through sprintf, even if @_ is empty. | ||||
379 | # This is to do proper '%%' translation. | ||||
380 | 2 | 100µs | 2 | 4.75ms | my $sql = $class->transform_sql($statement => @_); # spent 4.75ms making 2 calls to Class::DBI::transform_sql, avg 2.37ms/call |
381 | 2 | 225µs | 2 | 957µs | return $cache # spent 957µs making 2 calls to DBI::db::prepare_cached, avg 479µs/call |
382 | ? $dbh->prepare_cached($sql) | ||||
383 | : $dbh->prepare($sql); | ||||
384 | 13 | 322µs | }; | ||
385 | } | ||||
386 | |||||
387 | =head2 transform_sql | ||||
388 | |||||
389 | To make up for the limitations of bind parameters, $statement can contain | ||||
390 | sprintf() style formatting (ie. %s and such) to allow dynamically | ||||
391 | generated SQL statements (so to get a real percent sign, use '%%'). | ||||
392 | |||||
393 | The translation of the SQL happens in transform_sql(), which can be | ||||
394 | overridden to do more complex transformations. See L<Class::DBI> for an | ||||
395 | example. | ||||
396 | |||||
397 | =cut | ||||
398 | |||||
399 | # spent 51µs within Ima::DBI::transform_sql which was called 2 times, avg 26µs/call:
# 2 times (51µs+0s) by Class::DBI::transform_sql at line 154 of Class/DBI.pm, avg 26µs/call | ||||
400 | 2 | 17µs | my ($class, $sql, @args) = @_; | ||
401 | 2 | 43µs | return sprintf $sql, @args; | ||
402 | } | ||||
403 | |||||
404 | =head2 db_names / db_handles | ||||
405 | |||||
406 | my @database_names = Foo->db_names; | ||||
407 | my @database_handles = Foo->db_handles; | ||||
408 | my @database_handles = Foo->db_handles(@db_names); | ||||
409 | |||||
410 | Returns a list of the database handles set up for this class using | ||||
411 | set_db(). This includes all inherited handles. | ||||
412 | |||||
413 | db_names() simply returns the name of the handle, from which it is | ||||
414 | possible to access it by converting it to a method name and calling | ||||
415 | that db method... | ||||
416 | |||||
417 | my @db_names = Foo->db_names; | ||||
418 | my $db_meth = 'db_'.$db_names[0]; | ||||
419 | my $dbh = $foo->$db_meth; | ||||
420 | |||||
421 | Icky, eh? Fortunately, db_handles() does this for you and returns a | ||||
422 | list of database handles in the same order as db_names(). B<Use this | ||||
423 | sparingly> as it will connect you to the database if you weren't | ||||
424 | already connected. | ||||
425 | |||||
426 | If given @db_names, db_handles() will return only the handles for | ||||
427 | those connections. | ||||
428 | |||||
429 | These both work as either class or object methods. | ||||
430 | |||||
431 | =cut | ||||
432 | |||||
433 | sub db_names { @{ $_[0]->__Database_Names || [] } } | ||||
434 | |||||
435 | sub db_handles { | ||||
436 | my ($self, @db_names) = @_; | ||||
437 | @db_names = $self->db_names unless @db_names; | ||||
438 | return map $self->$_(), map "db_$_", @db_names; | ||||
439 | } | ||||
440 | |||||
441 | =head2 sql_names | ||||
442 | |||||
443 | my @statement_names = Foo->sql_names; | ||||
444 | |||||
445 | Similar to db_names() this returns the names of all SQL statements set | ||||
446 | up for this class using set_sql(), inherited or otherwise. | ||||
447 | |||||
448 | There is no corresponding sql_handles() because we can't know what | ||||
449 | arguments to pass in. | ||||
450 | |||||
451 | =cut | ||||
452 | |||||
453 | sub sql_names { @{ $_[0]->__Statement_Names || [] } } | ||||
454 | |||||
455 | =head1 Object Methods | ||||
456 | |||||
457 | =head2 db_* | ||||
458 | |||||
459 | $dbh = $obj->db_*; | ||||
460 | |||||
461 | This is how you directly access a database handle you set up with set_db. | ||||
462 | |||||
463 | The actual particular method name is derived from what you told set_db. | ||||
464 | |||||
465 | db_* will handle all the issues of making sure you're already | ||||
466 | connected to the database. | ||||
467 | |||||
468 | =head2 sql_* | ||||
469 | |||||
470 | $sth = $obj->sql_*; | ||||
471 | $sth = $obj->sql_*(@sql_pieces); | ||||
472 | |||||
473 | sql_*() is a catch-all name for the methods you set up with set_sql(). | ||||
474 | For instance, if you did: | ||||
475 | |||||
476 | Foo->set_sql('GetAllFoo', 'Select * From Foo', 'SomeDb'); | ||||
477 | |||||
478 | you'd run that statement with sql_GetAllFoo(). | ||||
479 | |||||
480 | sql_* will handle all the issues of making sure the database is | ||||
481 | already connected, and the statement handle is prepared. It returns a | ||||
482 | prepared statement handle for you to use. (You're expected to | ||||
483 | execute() it) | ||||
484 | |||||
485 | If sql_*() is given a list of @sql_pieces it will use them to fill in | ||||
486 | your statement, assuming you have sprintf() formatting tags in your | ||||
487 | statement. For example: | ||||
488 | |||||
489 | Foo->set_sql('GetTable', 'Select * From %s', 'Things'); | ||||
490 | |||||
491 | # Assuming we have created an object... this will prepare the | ||||
492 | # statement 'Select * From Bar' | ||||
493 | $sth = $obj->sql_Search('Bar'); | ||||
494 | |||||
495 | Be B<very careful> with what you feed this function. It cannot | ||||
496 | do any quoting or escaping for you, so it is totally up to you | ||||
497 | to take care of that. Fortunately if you have tainting on you | ||||
498 | will be spared the worst. | ||||
499 | |||||
500 | It is recommended you only use this in cases where bind parameters | ||||
501 | will not work. | ||||
502 | |||||
503 | =head2 DBIwarn | ||||
504 | |||||
505 | $obj->DBIwarn($what, $doing); | ||||
506 | |||||
507 | Produces a useful error for exceptions with DBI. | ||||
508 | |||||
509 | B<I'm not particularly happy with this interface> | ||||
510 | |||||
511 | Most useful like this: | ||||
512 | |||||
513 | eval { | ||||
514 | $self->sql_Something->execute($self->{ID}, @stuff); | ||||
515 | }; | ||||
516 | if($@) { | ||||
517 | $self->DBIwarn($self->{ID}, 'Something'); | ||||
518 | return; | ||||
519 | } | ||||
520 | |||||
521 | |||||
522 | =cut | ||||
523 | |||||
524 | sub DBIwarn { | ||||
525 | my ($self, $thing, $doing) = @_; | ||||
526 | my $errstr = "Failure while doing '$doing' with '$thing'\n"; | ||||
527 | $errstr .= $@ if $@; | ||||
528 | |||||
529 | require Carp; | ||||
530 | Carp::carp $errstr; | ||||
531 | |||||
532 | return 1; | ||||
533 | } | ||||
534 | |||||
535 | =head1 Modified database handle methods | ||||
536 | |||||
537 | Ima::DBI makes some of the methods available to your object that are | ||||
538 | normally only available via the database handle. In addition, it | ||||
539 | spices up the API a bit. | ||||
540 | |||||
541 | =head2 commit | ||||
542 | |||||
543 | $rc = $obj->commit; | ||||
544 | $rc = $obj->commit(@db_names); | ||||
545 | |||||
546 | Derived from $dbh->commit() and basically does the same thing. | ||||
547 | |||||
548 | If called with no arguments, it causes commit() to be called on all | ||||
549 | database handles associated with $obj. Otherwise it commits all | ||||
550 | database handles whose names are listed in @db_names. | ||||
551 | |||||
552 | Alternatively, you may like to do: $rc = $obj->db_Name->commit; | ||||
553 | |||||
554 | If all the commits succeeded it returns true, false otherwise. | ||||
555 | |||||
556 | =cut | ||||
557 | |||||
558 | sub commit { | ||||
559 | my ($self, @db_names) = @_; | ||||
560 | return grep(!$_, map $_->commit, $self->db_handles(@db_names)) ? 0 : 1; | ||||
561 | } | ||||
562 | |||||
563 | =head2 rollback | ||||
564 | |||||
565 | $rc = $obj->rollback; | ||||
566 | $rc = $obj->rollback(@db_names); | ||||
567 | |||||
568 | Derived from $dbh->rollback, this acts just like Ima::DBI->commit, | ||||
569 | except that it calls rollback(). | ||||
570 | |||||
571 | Alternatively, you may like to do: $rc = $obj->db_Name->rollback; | ||||
572 | |||||
573 | If all the rollbacks succeeded it returns true, false otherwise. | ||||
574 | |||||
575 | =cut | ||||
576 | |||||
577 | sub rollback { | ||||
578 | my ($self, @db_names) = @_; | ||||
579 | return grep(!$_, map $_->rollback, $self->db_handles(@db_names)) ? 0 : 1; | ||||
580 | } | ||||
581 | |||||
582 | =head1 EXAMPLE | ||||
583 | |||||
584 | package Foo; | ||||
585 | use base qw(Ima::DBI); | ||||
586 | |||||
587 | # Set up database connections (but don't connect yet) | ||||
588 | Foo->set_db('Users', 'dbi:Oracle:Foo', 'admin', 'passwd'); | ||||
589 | Foo->set_db('Customers', 'dbi:Oracle:Foo', 'Staff', 'passwd'); | ||||
590 | |||||
591 | # Set up SQL statements to be used through out the program. | ||||
592 | Foo->set_sql('FindUser', <<"SQL", 'Users'); | ||||
593 | SELECT * | ||||
594 | FROM Users | ||||
595 | WHERE Name LIKE ? | ||||
596 | SQL | ||||
597 | |||||
598 | Foo->set_sql('ChangeLanguage', <<"SQL", 'Customers'); | ||||
599 | UPDATE Customers | ||||
600 | SET Language = ? | ||||
601 | WHERE Country = ? | ||||
602 | SQL | ||||
603 | |||||
604 | # rest of the class as usual. | ||||
605 | |||||
606 | package main; | ||||
607 | |||||
608 | $obj = Foo->new; | ||||
609 | |||||
610 | eval { | ||||
611 | # Does connect & prepare | ||||
612 | my $sth = $obj->sql_FindUser; | ||||
613 | # bind_params, execute & bind_columns | ||||
614 | $sth->execute(['Likmi%'], [\($name)]); | ||||
615 | while( $sth->fetch ) { | ||||
616 | print $name; | ||||
617 | } | ||||
618 | |||||
619 | # Uses cached database and statement handles | ||||
620 | $sth = $obj->sql_FindUser; | ||||
621 | # bind_params & execute. | ||||
622 | $sth->execute('%Hock'); | ||||
623 | @names = $sth->fetchall; | ||||
624 | |||||
625 | # connects, prepares | ||||
626 | $rows_altered = $obj->sql_ChangeLanguage->execute(qw(es_MX mx)); | ||||
627 | }; | ||||
628 | unless ($@) { | ||||
629 | # Everything went okay, commit the changes to the customers. | ||||
630 | $obj->commit('Customers'); | ||||
631 | } | ||||
632 | else { | ||||
633 | $obj->rollback('Customers'); | ||||
634 | warn "DBI failure: $@"; | ||||
635 | } | ||||
636 | |||||
637 | |||||
638 | =head1 TODO, Caveat, BUGS, etc.... | ||||
639 | |||||
640 | =over 4 | ||||
641 | |||||
642 | =item I seriously doubt that it's thread safe. | ||||
643 | |||||
644 | You can bet cupcackes to sno-cones that much havoc will be wrought if | ||||
645 | Ima::DBI is used in a threaded Perl. | ||||
646 | |||||
647 | =item Should make use of private_* handle method to store information | ||||
648 | |||||
649 | =item The docs stink. | ||||
650 | |||||
651 | The docs were originally written when I didn't have a good handle on | ||||
652 | the module and how it will be used in practical cases. I need to | ||||
653 | rewrite the docs from the ground up. | ||||
654 | |||||
655 | =item Need to add debugging hooks. | ||||
656 | |||||
657 | The thing which immediately comes to mind is a Verbose flag to print | ||||
658 | out SQL statements as they are made as well as mention when database | ||||
659 | connections are made, etc... | ||||
660 | |||||
661 | =back | ||||
662 | |||||
663 | =head1 MAINTAINER | ||||
664 | |||||
665 | Tony Bowden <tony@tmtm.com> | ||||
666 | |||||
667 | =head1 ORIGINAL AUTHOR | ||||
668 | |||||
669 | Michael G Schwern <schwern@pobox.com> | ||||
670 | |||||
671 | =head1 LICENSE | ||||
672 | |||||
673 | This module is free software. You may distribute under the same terms | ||||
674 | as Perl itself. IT COMES WITHOUT WARRANTY OF ANY KIND. | ||||
675 | |||||
676 | =head1 THANKS MUCHLY | ||||
677 | |||||
678 | Tim Bunce, for enduring many DBI questions and adding Taint, | ||||
679 | prepare_cached and connect_cached methods to DBI, simplifying this | ||||
680 | greatly! | ||||
681 | |||||
682 | Arena Networks, for effectively paying for Mike to write most of this | ||||
683 | module. | ||||
684 | |||||
685 | =head1 SEE ALSO | ||||
686 | |||||
687 | L<DBI>. | ||||
688 | |||||
689 | You may also choose to check out L<Class::DBI> which hides most of this | ||||
690 | from view. | ||||
691 | |||||
692 | =cut | ||||
693 | |||||
694 | 1 | 16µs | return 1001001; | ||
# spent 180µs within Ima::DBI::CORE:subst which was called 27 times, avg 7µs/call:
# 13 times (112µs+0s) by Ima::DBI::set_sql at line 353 of Ima/DBI.pm, avg 9µs/call
# 13 times (60µs+0s) by Ima::DBI::set_sql at line 356 of Ima/DBI.pm, avg 5µs/call
# once (8µs+0s) by Ima::DBI::set_db at line 267 of Ima/DBI.pm |