1NAME
2 DBIx::TableHash - Tie a hash to a mysql table + SQL utils
3
4SYNOPSIS
5 use DBIx::TableHash;
6 my $DBHash = DBIx::TableHash->create_or_die
7 (my $Params =
8 {
9 DBIDriver => 'mysql',
10 Database => 'mydatabase',
11 HostName => 'localhost',
12 Port => undef,
13 Login => '',
14 Password => '',
15
16 TableName => 'SalesPeople',
17 KeyField => 'FullName',
18
19 ## For multi-key lookup:
20 FixedKeys => {AreaCode => 415,
21 StatusCode => 'Active',
22 RecordType => 'Primary'},
23
24 ## To retrieve a single value:
25 ValueField => 'PhoneNumber',
26
27 ## ... or for "multi-value" retrieval...
28 ValueField => undef,
29
30 ## ... optionally specifying...
31 RetrieveFields => [qw(Title Territory Quota)],
32
33 ## For caching:
34 CacheMode => 'CacheBeforeIterate'
35 ## or...
36 CacheMode => 'CacheOneTime'
37 ## or...
38 CacheMode => 'CacheNone'
39 }
40 );
41
42 my %DBHash; tie(%DBHash, 'DBIx::TableHash', $Params);
43
44 my $DBHash = DBIx::TableHash->create($Params) or die "Help!";
45 my $DBHash = DBIx::TableHash->create_or_die($Params);
46
47 my $DBHash = DBIx::TableHash->create_copy($Params) or die "Help!";
48 my $DBHash = DBIx::TableHash->create_copy_or_die($Params);
49
50OVERVIEW
51 All parameters are passed via a single anonymous hash.
52
53 All parameters are optional, but you'll almost always need to specify
54 Database, TableName, and KeyField.
55
56 Omitting ValueField puts the hash in "multi-value" mode, where you
57 store/retrieve a hash of fields/values instead of a single value. In
58 "multi-value" mode all fields in each record are retrieved on every
59 fetch; RetrieveFields limits fields retrieved to a specified list.
60
61 Specifying FixedKeys puts the hash in "multi-key" mode, in which only a
62 subset of the database table, corresopnding to records that match the
63 spec in FixedKeys, is operated on.
64
65 Cache modes reduce querying, but lose synchronization and hog memory.
66
67 The object is designed to be easy subclass. Try making a subclass that
68 sets defaults for all or most of the parameters, so the caller doesn't
69 have to supply any at instantiation time.
70
71 "create_copy" methods efficiently create and return potentially huge
72 untied hash "snapshot" of the same data that would have been retrieved
73 by the corresponding tied hash.
74
75DETAILS
76 The DBHash object is designed to tie a hash to a table or a subset of
77 records in a table in a DBI database (only tested with mysql in the
78 current version, but expected to work with any vendor).
79
80 If the table only has a single KeyField, which this modules assumes to
81 be a unique key field in the table, then the hash keys are stored and
82 retrieved in that field, and the values are saved in and returned from
83 the ValueField. Records are automatically created and deleted as the
84 hash is used like any other hash. (If the table is read-only, be sure
85 not to try to store into the tied hash!)
86
87 To access only a subset of the records in a table, you may specify hash
88 of "FixedKeys", which is a hash mapping OTHER field names to fixed
89 values that those fields must have for all lookups, updates, and inserts
90 done via the hash interface. This sets up a virtual hash corresponding
91 to a subset of the table where N key fields are fixed at given values
92 and a different key field may vary.
93
94 There are several ways to use this module.
95
96 Quick and dirty mode (single-key, single-value) using tie:
97
98 use DBIx::TableHash;
99 my %PhoneNumbers;
100 tie (%PhoneNumbers, 'DBIx::TableHash',
101 {Database => 'mydatabase',
102 TableName => 'SalesPeople',
103 KeyField => 'FullName',
104 ValueField => 'PhoneNumber'})
105 or die "Failed to connect to database";
106
107 Then you can use %PhoneNumbers like any hash mapping FullName to
108 PhoneNumber. Any retrieval of data results in corresponding SQL queries
109 being made to the database. Modifying the hash modifies the database.
110
111 Even quicker mode using create():
112
113 For convenience, you can use the create() class method to do the tying
114 for you. It creates an anonymous hash, ties it and, returns it. It takes
115 the same parameters as new() and tie().
116
117 use DBIx::TableHash;
118 my $PhoneNumbers = DBIx::TableHash->create(......)
119 or die "Failed to connect to database";
120
121 Quicker still using create_or_die():
122
123 use DBIx::TableHash;
124 my $PhoneNumbers = DBIx::TableHash->create_or_die(......);
125
126 create() carps and returns undef if it can't connect to the database.
127
128 create_or_die() croaks (dies) your program, with the same error message
129 as create() would have given.
130
131 Normally, create() will carp() (warn) you with an error message upon
132 failure, and return undef.
133
134 If you would have handled your error by saying "or die", and ar
135 comfortable with create's error message rather than your own, then
136 create_or_die() is for you.
137
138 Using one of the create() methods instead of new() and tie() works with
139 all of the different modes discussed below, and all parameters are the
140 same either way.
141
142 Cooler subclassing mode:
143
144 You can create a simple subclass that provides default parmas in an
145 initialize method so they don't have to be provided by the caller ...
146
147 ### MyCompany/SalesPhoneHash.pm:
148
149 #!/usr/bin/perl
150
151 use strict;
152
153 package MyCompany::SalesPhoneHash;
154 use vars qw(@ISA);
155 use DBIx::TableHash;
156 @ISA = qw(DBIx::TableHash);
157
158 sub initialize
159 {
160 my $this = shift;
161
162 $this->{Database} ||= 'mydatabase'; ## Name of database to connect to.
163 $this->{TableName} ||= 'SalesPeople'; ## Table in which to store the data
164 $this->{KeyField} ||= 'FullName'; ## Name of the key field
165 $this->{ValueField} ||= 'PhoneNumber'; ## Name of the value field.
166
167 done:
168 return($this->SUPER::initialize());
169 }
170 1;
171
172 Then to use the object, your script merely does:
173
174 use MyCompany::SalesPhoneHash;
175 my %PhoneNumbers = MyCompany::SalesPhoneHash->create_or_die();
176
177 Of course, when instantiating a subclass, if you wish you can still
178 override any parameters you wish, as long as the initialize() method in
179 the subclass uses ||= rather than = to set defaults for any unspecified
180 parameters.
181
182 Multi-key mode:
183
184 You may also use the "FixedKeys" parameter to specify a hash of some
185 additional key fields and their fixed values that must match exactly for
186 any records that are retrieved, deleted, or created by the tied object,
187 effectively allowing the hash to operate on only a subset of the data in
188 the database. This is typically helpful in a multi-keyed table where,
189 for the purposes of your script, all key values should be fixed except
190 one (and that one is the hash key).
191
192 use DBIx::TableHash;
193 my $PhoneNumbers =
194 DBIx::TableHash->
195 create_or_die(
196 {Database => 'mydatabase',
197 TableName => 'SalesPeople',
198 KeyField => 'FullName',
199 ValueField => 'PhoneNumbers',
200 FixedKeys =>
201 {AreaCode => 415,
202 StatusCode => 'Active',
203 RecordType => 'Primary'}});
204
205 Multi-value mode:
206
207 If instead of getting and setting a single value, you'd like to get or
208 set a hash of all fields in the record, simply don't specify ValueField,
209 and the object will use "multi-value" mode, where an entire record, as a
210 hash, is gotten or set on each fetch or store. Feel free to combine this
211 mode with multi-key mode.
212
213 When storing a record in multi-value mode, if the record already exists,
214 only the specified fields are overwritten. If it did not already exist,
215 then only the specified fields will be written and the others will be
216 NULL or defaulted according to the table schema.
217
218 When storing a record in multi-value mode, you can't change the values
219 of the primary key field or any other key field specified in FixedKeys
220 (if any), since that would mess up the whole point of this module which
221 is to leave the main key and fixed keys fixed while mucking with the
222 other values in the record. Any changed values in key fields are simply
223 ignored.
224
225 use DBIx::TableHash;
226 my $SalesPeopleTable =
227 DBIx::TableHash->
228 create_or_die(
229 {Database => 'mydatabase',
230 TableName => 'SalesPeople',
231 KeyField => 'FullName'});
232
233 my $SalesPersonFullName = "Joe Jones";
234 my $EntireRecord = $SalesPeopleTable->{$SalesPersonFullName};
235
236 When fetching records in multi-value mode, you can limit the list of
237 returned fields to a subset of all available fields in case there might
238 be some very big ones that you don't want to waste bandwidth getting.
239 Just set the RetrieveFields parameter to an anonymous list of the fields
240 you care to retrieve. (This setting does not limit the fields you can
241 SET, just the ones that get retrieved.)
242
243 use DBIx::TableHash;
244 my $SalesPeopleTable =
245 DBIx::TableHash->
246 create_or_die(
247 {Database => 'mydatabase',
248 TableName => 'SalesPeople',
249 KeyField => 'FullName',
250 RetrieveFields=> [qw(Territory Quota)]});
251
252 Warning:
253
254 In multi-value mode, you might expect that this:
255
256 $Hash->{$MyKey}->{FieldX} = 'foo';
257
258 would set the value of the FieldX field in the appropriate record in the
259 database. IT DOES NOT.
260
261 This is because the anonymous hash returned by $Hash->{$MyKey} is not in
262 any way tied back to the database. You'd have to retrieve the record
263 hash, change any value in it, and then set $Hash->{$MyKey} back to it.
264
265 Making the above syntax work with a multi-valued tied hash to set a
266 value in the database is a possible future enhancement under
267 consideration by the author. Let me know if you would like to have that
268 work.
269
270 In the meanwhile, here's how you do could do it:
271
272 (my $Record = $Hash->{$MyKey})->{FieldX} = 'foo';
273 $Hash->{$MyKey}->{FieldX} = $Record;
274
275 WARNING: If you use the above approach to update a record in multi-value
276 mode, beware that there's potentially a race condition in the above code
277 if someone else updates the same record after you've copied it but
278 before you've modified and set it. So use this technique with caution
279 and understanding. If in doubt, don't use this module and instead use an
280 SQL query to update the record in a single transaction. Only you know
281 the usage patterns of your database, the concurrency issues, and the
282 criticality of errors.
283
284 Caching modes:
285
286 The object has several ways it can cache data to help minimize the
287 number of SQL queries to the database, at the expense of potentially
288 dramatically increased memory usage. The following cache parameters can
289 be specified to enable caching:
290
291 CacheMode => 'CacheBeforeIterate'
292
293 CacheMode => 'CacheOneTime'
294
295 To disable caching, specify:
296
297 CacheMode => 'CacheNone'
298
299 (You can also assign undef to CacheMode, but you'll get warnings.)
300
301 Normally, every time you fetch a value from the hash, it makes an SQL
302 query to the database. This, of course, is the intended and normal mode
303 of operation.
304
305 Unfortunately, in Perl, just calling values(%Hash) or each(%Hash) or
306 even copying the hash with {%Hash} results in a separate FETCH, and
307 consequently, a separate SQL query made by this module, for each item.
308 This could result in thousands of queries just to fetch all the values
309 from a thousand-item table in the database.
310
311 However, often you want to iterate over all the elements of a hash
312 without it having to go back to the database and issue another query for
313 each item that you retrieve.
314
315 Using the 'CacheBeforeIterate' mode, all keys and values are cached upon
316 each call to FIRSTKEYS (i.e. at the start of any iteration or
317 enumeration). Then, any subsequent calls to FETCH data from the hash
318 retrieve it from the cache instead of doing an SQL query. STORING or
319 DELETING any items from the hash results in them being stored and
320 deleted from both the database and the cache.
321
322 Using the CacheOneTime mode, the full cache is built at object
323 instantiation and time never fully rebuilt. In fact, its contents never
324 change unless you make alterations by using it to store into and/or
325 delete from the database.
326
327 CACHE WARNING: With both caching modes, of course, you must be
328 comfortable with the fact that the data being retrieved is a "snapshot"
329 of the database and consequently will not reflect updates done by other
330 parties during the lifetime of the object; it will only reflect updates
331 that you make by storing or deleting values from it. If other people are
332 using the database simultaneously, your cache and the actual data could
333 "drift" out of agreement. This is mainly dangerous to you, not others,
334 unless you then go make updates to the data based on potentially
335 outdated values.
336
337 All modes may be combined...
338
339 All modes and parameters are orthogonal, so any combination of
340 parameters may be specified, with the exception that the RetrieveFields
341 parameter is only meaningful when ValueField is not unspecified.
342
343 With subclassing, you may create objects that pre-specify any
344 parameters, even those that affect the major modes of operation. For
345 example, you may combine the subclassing technique and the multi-key
346 mode to make an object that accesses only the appropriate subset of a
347 multi-keyed table without requiring any parameters to be supplied by the
348 caller.
349
350 Getting a COPY of the data instead of a tied hash:
351
352 What if you just want a big copy -- a snapshot -- of the data in the
353 table, in a regular old hash that's no longer tied to the database at
354 all? (Memory constraints be damned!)
355
356 Just use the create_copy() or create_copy_or_die() methods. They work
357 just like create() and create_or_die(), but instead of returning a tied
358 object, they just return a potentially huge hash containing a copy of
359 all the data.
360
361 In other words:
362
363 create_copy() is equivalent to: {%{create() || {} }}
364 create_copy_or_die() is equivalent to: {%{create_or_die()}}
365
366 ... but the _copy methods are more efficient because internally, a
367 caching mode is used to minimize the queries to the database and
368 generate the hash as efficiently as possible.
369
370 In all other respects, create_copy() and create_copy_or_die() perform
371 exactly like their non-copying namesakes, taking all the same
372 parameters, except CacheMode which is not relevant when making a static
373 copy.
374
375 Please remember that the object returned by the _copy methods is no
376 longer tied to the database.
377
378PARAMETER SUMMARY
379 The full list of recognized parameters is:
380
381 DBI Parameters
382
383 Param Default Description
384 ------------------------------------------------------------------------
385 DBIDriver 'mysql' Name of DBI driver to try to use (only
386 mysql has currently been tested by the
387 author).
388
389 HostName 'localhost' Host name containing the database and table;
390
391 Port undef Port number if different from the standard.
392
393 Login '' Login to use when connecting, if any.
394
395 Password '' Password to use when connecting, if any.
396
397 SQL Parameters
398
399 Param Default Description
400 ------------------------------------------------------------------------
401 Database '' Name of database to connect to.
402
403 TableName '' Table to connect to.
404
405 KeyField '' Name of field in which lookup key is found.
406
407 ValueField '' Name of field to pull value from.
408 If empty or undef, then a
409 multi-value hash is used both for
410 saving and retrieving. This is
411 called "multi-value mode".
412
413 Module Parameters
414
415 Param Default Description
416 ------------------------------------------------------------------------
417 FixedKeys {} If supplied, gives names and
418 fixed, hardcoded values that other
419 keys in the table must have; this
420 effectively limits the scope of
421 the tied hash from operating over
422 the entire table to operating over
423 just the subset of records that
424 match the values in FixedKeys.
425 This is called "multi-key mode".
426
427 RetrieveFields [] In multi-value mode, limits the
428 fields that are retrieved; default
429 is all fields in the record.
430
431SUPPORT
432 I am unable to provide any technical support for this module. The whole
433 reason I had to make it was that I was way too busy (lazy?) to write all
434 that SQL code...
435
436 But you are encouraged to send patches, bug warnings, updates, thanks,
437 or suggestions for improvements to the author as listed below.
438
439 Just be aware that I may not have time to respond. Please be sure to put
440 the name of this module somewhere in the Subject line.
441
442 The code is a pretty simple tied hash implementation, so you're on your
443 own to debug it. If you're having trouble debugging via the "tie"
444 interface, try instantiating an object directly (or retrieving it when
445 you tie (see perltie)) and calling its methods individually. Use the
446 debugger or Data::Dumper to dump intermediate values at key points, or
447 whatever it takes. Use your database server logs if you want to see what
448 SQL code is getting generated. Or contribute a debugging mode to this
449 module which prints out or logs the SQL statements before executing
450 them.
451
452BUGS/GOTCHAS
453 Problem: If you iterate or enumerate the hash, all keys get pulled in
454 from the database and stay stored in memory for the lifetime of the
455 object. FIRSTKEY, which is called every time you do a keys(), each() or
456 any full iteration or enumeration over the tied hash (such as copying
457 it) retrieves and hangs on to a full list of all keys in KeyField. If
458 the keys are long or there are lots of them, this could be a memory
459 problem. (Don't confuse this with CacheMode in which BOTH keys AND
460 values are stored in memory.)
461
462 Solutions:
463
464 1) Don't iterate or enumerate. Just fetch and store.
465 2) Only iterate or enumerate on short tables.
466 3) LValue or RValue hash slices should be safe to do.
467
468INSTALLATION
469 Using CPAN module:
470
471 perl -MCPAN -e 'install DBIx::TableHash'
472
473 Or manually:
474
475 tar xzvf DBIx-TableHash*gz
476 cd DBIx-TableHash-?.??
477 perl Makefile.PL
478 make
479 make test
480 make install
481
482SEE ALSO
483 The DBIx::TableHash home page:
484
485 http://christhorman.com/projects/perl/DBIx-TableHash/
486
487 The implementation in TableHash.pm.
488
489 The perlref and perltie manual pages.
490
491 The mysql home page:
492
493 http://mysql.com/
494
495THANKS
496 Thanks to Mark Leighton Fisher <fisherm@tce.com> for providing a patch
497 to fix -w support (change in standard "none" setting of CacheMode from
498 undef to CacheNone).
499
500AUTHOR
501 Chris Thorman <chthorman@cpan.org>
502
503 Copyright (c) 1995-2002 Chris Thorman. All rights reserved.
504
505 This program is free software; you can redistribute it and/or modify it
506 under the same terms as Perl itself.
507
508