File Coverage

blib/lib/Persistent/DBM.pm
Criterion Covered Total %
statement 75 77 97.4
branch 24 44 54.5
condition 0 2 0.0
subroutine 12 12 100.0
pod 1 1 100.0
total 112 136 82.3


line stmt bran cond sub pod time code
1             ########################################################################
2             # File: DBM.pm
3             # Author: David Winters
4             # RCS: $Id: DBM.pm,v 1.7 2000/02/26 03:38:28 winters Exp winters $
5             #
6             # An abstract class that implements object persistence using a DBM file.
7             # This class inherits from other persistent classes.
8             #
9             # This file contains POD documentation that may be viewed with the
10             # perldoc, pod2man, or pod2html utilities.
11             #
12             # Copyright (c) 1998-2000 David Winters. All rights reserved.
13             # This program is free software; you can redistribute it
14             # and/or modify it under the same terms as Perl itself.
15             ########################################################################
16              
17             package Persistent::DBM;
18             require 5.004;
19              
20 6     6   7270 use strict;
  6         12  
  6         266  
21 6     6   30 use vars qw(@ISA $VERSION $REVISION);
  6         11  
  6         468  
22              
23 6     6   34 use Carp;
  6         12  
  6         487  
24 6     6   5618 use English;
  6         20440  
  6         40  
25 6     6   3535 use Fcntl qw(:flock O_CREAT O_RDWR); # import LOCK_* constants
  6         13  
  6         2052  
26              
27             ### we are a subclass of the all-powerful Persistent::Memory class ###
28 6     6   6990 use Persistent::Memory;
  6         21  
  6         12800  
29             @ISA = qw(Persistent::Memory);
30              
31             ### copy version number from superclass ###
32             $VERSION = $Persistent::Memory::VERSION;
33             $REVISION = (qw$Revision: 1.7 $)[1];
34              
35             =head1 NAME
36              
37             Persistent::DBM - A Persistent Class implemented using a DBM File
38              
39             =head1 SYNOPSIS
40              
41             use Persistent::DBM;
42             use English; # import readable variable names like $EVAL_ERROR
43              
44             eval { ### in case an exception is thrown ###
45              
46             ### allocate a persistent object ###
47             my $person = new Persistent::DBM('people.dbm');
48              
49             ### define attributes of the object ###
50             $person->add_attribute('firstname', 'ID', 'VarChar', undef, 10);
51             $person->add_attribute('lastname', 'ID', 'VarChar', undef, 20);
52             $person->add_attribute('telnum', 'Persistent',
53             'VarChar', undef, 15);
54             $person->add_attribute('bday', 'Persistent', 'DateTime', undef);
55             $person->add_attribute('age', 'Transient', 'Number', undef, 2);
56              
57             ### query the datastore for some objects ###
58             $person->restore_where(qq{
59             lastname = 'Flintstone' and
60             telnum =~ /^[(]?650/
61             });
62             while ($person->restore_next()) {
63             printf "name = %s, tel# = %s\n",
64             $person->firstname . ' ' . $person->lastname,
65             $person->telnum;
66             }
67             };
68              
69             if ($EVAL_ERROR) { ### catch those exceptions! ###
70             print "An error occurred: $EVAL_ERROR\n";
71             }
72              
73             =head1 ABSTRACT
74              
75             This is a Persistent class that uses DBM files to store and retrieve
76             objects. This class can be instantiated directly or subclassed. The
77             methods described below are unique to this class, and all other
78             methods that are provided by this class are documented in the
79             L documentation. The L documentation has a
80             very thorough introduction to using the Persistent framework of
81             classes.
82              
83             This class is part of the Persistent base package which is available
84             from:
85              
86             http://www.bigsnow.org/persistent
87             ftp://ftp.bigsnow.org/pub/persistent
88              
89             =head1 DESCRIPTION
90              
91             Before we get started describing the methods in detail, it should be
92             noted that all error handling in this class is done with exceptions.
93             So you should wrap an eval block around all of your code. Please see
94             the L documentation for more information on exception
95             handling in Perl.
96              
97             =head1 METHODS
98              
99             =cut
100              
101             ########################################################################
102             #
103             # -----------------------------------------------------------
104             # PUBLIC METHODS OVERRIDDEN (REDEFINED) FROM THE PARENT CLASS
105             # -----------------------------------------------------------
106             #
107             ########################################################################
108              
109             ########################################################################
110             # initialize
111             ########################################################################
112              
113             =head2 new -- Object Constructor
114              
115             use Persistent::DBM;
116              
117             eval {
118             my $obj = new Persistent::DBM($file, $field_delimiter, $type);
119             };
120             croak "Exception caught: $@" if $@;
121              
122             Allocates an object. This method throws Perl execeptions so use it
123             with an eval block.
124              
125             Parameters:
126              
127             =over 4
128              
129             =item These are the same as for the I method below.
130              
131             =back
132              
133             =cut
134              
135             ########################################################################
136             # datastore
137             ########################################################################
138              
139             =head2 datastore -- Sets/Returns the Data Store Parameters
140              
141             eval {
142             ### set the data store ###
143             $obj->datastore($file, $field_delimiter, $type);
144              
145             ### get the data store ###
146             $file = $obj->datastore();
147             };
148             croak "Exception caught: $@" if $@;
149              
150             Returns (and optionally sets) the data store of the object. This
151             method throws Perl execeptions so use it with an eval block.
152              
153             Parameters:
154              
155             =over 4
156              
157             =item I<$file>
158              
159             File to use as the data store.
160              
161             =item I<$field_delimiter>
162              
163             Delimiter used to separate the attributes of the object in the data
164             store. This argument is optional and will be initialized to the value
165             of the special Perl variable I<$;> (or I<$SUBSCRIPT_SEPARATOR> if you
166             are using the English module) as a default or if set to undef.
167              
168             =item I<$type>
169              
170             Type of DBM file to use. This is probably one of these: NDBM_File,
171             DB_File, GDBM_File, SDBM_File, or ODBM_File. This argument is
172             optional and will default to C. See the C
173             documentation for more information.
174              
175             =back
176              
177             Returns:
178              
179             =over 4
180              
181             =item I<$file>
182              
183             File used as the data store.
184              
185             =back
186              
187             =cut
188              
189             sub datastore {
190 2 50   2 1 7 (@_ > 0) or croak 'Usage: $obj->datastore([$file], [$delimiter], [$type])';
191 2         3 my $this = shift;
192 2 50       5 ref($this) or croak "$this is not an object";
193              
194 2         14 $this->_trace();
195              
196             ### set it ###
197 2 50       9 $this->{DataStore}->{File} = shift if @_; ## file name ###
198 2 50       6 $this->field_delimiter(shift) if @_; ### field delimiter ###
199 2 50       5 if (@_) { ### DBM type ###
200 0   0     0 $this->{DataStore}->{Module} = shift || 'AnyDBM_File';
201             } else {
202 2         6 $this->{DataStore}->{Module} = 'AnyDBM_File';
203             }
204 2         175 eval "require $this->{DataStore}->{Module}";
205              
206             ### return it ###
207 2         5033 $this->{DataStore}->{File};
208             }
209              
210             ########################################################################
211             # insert
212             ########################################################################
213              
214             =head2 insert -- Insert an Object into the Data Store
215              
216             eval {
217             $obj->insert();
218             };
219             croak "Exception caught: $@" if $@;
220              
221             Inserts an object into the data store. This method throws Perl
222             execeptions so use it with an eval block.
223              
224             Parameters:
225              
226             =over 4
227              
228             =item None.
229              
230             =back
231              
232             Returns:
233              
234             =over 4
235              
236             =item None.
237              
238             =back
239              
240             See the L documentation for more information.
241              
242             =cut
243              
244             ########################################################################
245             # update
246             ########################################################################
247              
248             =head2 update -- Update an Object in the Data Store
249              
250             eval {
251             $obj->update();
252             };
253             croak "Exception caught: $@" if $@;
254              
255             Updates an object in the data store. This method throws Perl
256             execeptions so use it with an eval block.
257              
258             Parameters:
259              
260             =over 4
261              
262             =item I<@id>
263              
264             Values of the Identity attributes of the object. This argument is
265             optional and will default to the Identifier values of the object as
266             the default.
267              
268             This argument is useful if you are updating the Identity attributes of
269             the object and you already have all of the attribute values so you do
270             not need to restore the object (like a CGI request with hidden fields,
271             maybe). So you can just set the Identity attributes of the object to
272             the new values and then pass the old Identity values as arguments to
273             the I method. For example, if Pebbles Flintstone married Bam
274             Bam Rubble, then you could update her last name like this:
275              
276             ### Pebbles already exists in the data store, but we don't ###
277             ### want to do an extra restore because we already have ###
278             ### all of the attribute values ###
279              
280             $person->lastname('Rubble');
281             $person->firstname('Pebbles');
282             ### set the rest of the attributes ... ###
283              
284             $person->update('Flintstone', 'Pebbles');
285              
286             Or, if don't want to set all of the object's attributes, you can just
287             restore it and then update it like this:
288              
289             ### restore object from data store ###
290             if ($person->restore('Flintstone', 'Pebbles')) {
291             $person->lastname('Rubble');
292             $person->update();
293             }
294              
295             =back
296              
297             Returns:
298              
299             =over 4
300              
301             =item I<$flag>
302              
303             A true value if the object previously existed in the data store (it
304             was updated), and a false value if not (it was inserted).
305              
306             =back
307              
308             See the L documentation for more information.
309              
310             =cut
311              
312             ########################################################################
313             # save
314             ########################################################################
315              
316             =head2 save -- Save an Object to the Data Store
317              
318             eval {
319             $person->save();
320             };
321             croak "Exception caught: $@" if $@;
322              
323             Saves an object to the data store. The object is inserted if it does
324             not already exist in the data store, otherwise, it is updated. This
325             method throws Perl execeptions so use it with an eval block.
326              
327             Parameters:
328              
329             =over 4
330              
331             =item None.
332              
333             =back
334              
335             Returns:
336              
337             =over 4
338              
339             =item I<$flag>
340              
341             A true value if the object previously existed in the data store (it
342             was updated), and a false value if not (it was inserted).
343              
344             =back
345              
346             See the L documentation for more information.
347              
348             =cut
349              
350             ########################################################################
351             # delete
352             ########################################################################
353              
354             =head2 delete -- Delete an Object from the Data Store
355              
356             eval {
357             $obj->delete();
358             ### or ###
359             $obj->delete(@id);
360             };
361             croak "Exception caught: $@" if $@;
362              
363             Deletes an object from the data store. This method throws Perl
364             execeptions so use it with an eval block.
365              
366             Parameters:
367              
368             =over 4
369              
370             =item I<@id>
371              
372             Values of the Identity attributes of the object. This argument is
373             optional and will default to the Identifier values of the object as
374             the default.
375              
376             =back
377              
378             Returns:
379              
380             =over 4
381              
382             =item I<$flag>
383              
384             A true value if the object previously existed in the data store (it
385             was deleted), and a false value if not (nothing to delete).
386              
387             =back
388              
389             See the L documentation for more information.
390              
391             =cut
392              
393             ########################################################################
394             # restore
395             ########################################################################
396              
397             =head2 restore -- Restore an Object from the Data Store
398              
399             eval {
400             $obj->restore(@id);
401             };
402             croak "Exception caught: $@" if $@;
403              
404             Restores an object from the data store. This method throws Perl
405             execeptions so use it with an eval block.
406              
407             Parameters:
408              
409             =over 4
410              
411             =item I<@id>
412              
413             Values of the Identity attributes of the object. This method throws
414             Perl execeptions so use it with an eval block.
415              
416             =back
417              
418             Returns:
419              
420             =over 4
421              
422             =item I<$flag>
423              
424             A true value if the object previously existed in the data store (it
425             was restored), and a false value if not (nothing to restore).
426              
427             =back
428              
429             See the L documentation for more information.
430              
431             =cut
432              
433             ########################################################################
434             # restore_where
435             ########################################################################
436              
437             =head2 restore_where -- Conditionally Restoring Objects
438              
439             use Persistent::DBM;
440              
441             eval {
442             my $person = new Persistent::DBM('people.dbm', '|', 'NDBM_File');
443             $person->restore_where(
444             "lastname = 'Flintstone' and telnum =~ /^[(]?650/",
445             "lastname, firstname, telnum DESC"
446             );
447             while ($person->restore_next()) {
448             print "Restored: "; print_person($person);
449             }
450             };
451             croak "Exception caught: $@" if $@;
452              
453             Restores objects from the data store that meet the specified
454             conditions. The objects are returned one at a time by using the
455             I method and in a sorted order if specified. This
456             method throws Perl execeptions so use it with an eval block.
457              
458             Since this is a Perl based Persistent class, the I
459             method expects the I<$where> argument to use Perl expressions.
460              
461             Parameters:
462              
463             =over 4
464              
465             =item I<$where>
466              
467             Conditional expression for the requested objects. The format of this
468             expression is similar to a SQL WHERE clause. This argument is
469             optional.
470              
471             =item I<$order_by>
472              
473             Sort expression for the requested objects. The format of this
474             expression is similar to a SQL ORDER BY clause. This argument is
475             optional.
476              
477             =back
478              
479             Returns:
480              
481             =over 4
482              
483             =item I<$num_of_objs>
484              
485             The number of objects that match the conditions.
486              
487             =back
488              
489             See the L documentation for more information.
490              
491             =cut
492              
493             ########################################################################
494             #
495             # ---------------
496             # PRIVATE METHODS
497             # ---------------
498             #
499             ########################################################################
500              
501             ########################################################################
502             # Function: _load_datastore
503             # Description: Loads the datastore into a hash and returns
504             # a reference to it.
505             # In this case, the DBM file is tied to a hash.
506             # Parameters: None.
507             # Returns: $store = reference to the datstore
508             ########################################################################
509              
510             sub _load_datastore {
511 5 50   5   11 (@_ > 0) or croak 'Usage: $obj->_load_datastore()';
512 5         8 my $this = shift;
513 5 50       13 ref($this) or croak "$this is not an object";
514              
515 5         13 $this->_trace();
516              
517             ### get the DBM file info ###
518 5         11 my $file = $this->{DataStore}->{File};
519 5         19 my $delimiter = $this->field_delimiter();
520              
521             ### tie the DBM file to a hash ###
522 5         14 my $href = {};
523 5 50       299 tie(%$href, $this->{DataStore}->{Module}, $file, O_CREAT|O_RDWR, 0644) or
524             croak "Can't open (tie) $file: $!";
525              
526             ### save the hash ref ###
527 5         23 $this->{DataStore}->{Hash} = $href;
528             }
529              
530             ########################################################################
531             # Function: _flush_datastore
532             # Description: Flushes the hash containing the data back to the datastore.
533             # In this case, the DBM file is untied (closed).
534             # Parameters: None.
535             # Returns: None.
536             ########################################################################
537              
538             sub _flush_datastore {
539 4 50   4   11 (@_ > 0) or croak 'Usage: $obj->_flush_datastore()';
540 4         4 my $this = shift;
541 4 50       9 ref($this) or croak "$this is not an object";
542              
543 4         11 $this->_trace();
544              
545 4         10 $this->_close_datastore(@_);
546             }
547              
548             ########################################################################
549             # Function: _close_datastore
550             # Description: Closes the datastore.
551             # In this case, the DBM file is untied (closed).
552             # Parameters: None.
553             # Returns: None.
554             ########################################################################
555              
556             sub _close_datastore {
557 5 50   5   12 (@_ > 0) or croak 'Usage: $obj->_close_datastore()';
558 5         7 my $this = shift;
559 5 50       11 ref($this) or croak "$this is not an object";
560              
561 5         12 $this->_trace();
562              
563             ### close the DBM file ###
564 5 50       15 if (defined $this->{DataStore}->{Hash}) {
565              
566             ### untie the DBM file and clear out ref to hash ###
567 5         4 untie(%{$this->{DataStore}->{Hash}});
  5         101  
568 5         20 delete $this->{DataStore}->{Hash};
569             } else {
570 0         0 croak "No hash to untie from DBM file";
571             }
572             }
573              
574             ########################################################################
575             # Function: _lock_datastore
576             # Description: Locks the datastore for query or update.
577             # For datastore query, use a 'SHARED' lock.
578             # For datastore update, use a 'MUTEX' lock.
579             # Parameters: $lock_type = 'SHARED' or 'MUTEX'
580             # 'SHARED' is for read-only.
581             # 'MUTEX' is for read/write.
582             # Returns: None.
583             ########################################################################
584              
585             sub _lock_datastore {
586 5 50   5   12 (@_ > 0) or croak 'Usage: $obj->_lock_datastore($lock_type)';
587 5         8 my($this, $lock_type) = @_;
588 5 50       11 ref($this) or croak "$this is not an object";
589              
590 5         13 $this->_trace();
591              
592             ### set the flock and open types ###
593 5         7 my $flock_type = LOCK_SH;
594 5         7 my $open_type = '<';
595 5 100       18 if ($lock_type =~ /ex/i) {
596 4         4 $flock_type = LOCK_EX;
597 4         6 $open_type = '>';
598             }
599              
600             ### get the file info ###
601 5         17 my $file = $this->{DataStore}->{File};
602              
603             ### create the file if it does not exist ###
604 5 100       108 if (! -e "$file.lock") {
605 1 50       112 open(LOCK_FH, ">$file.lock") or croak "Can't create $file.lock: $!";
606 1         13 close(LOCK_FH);
607             }
608              
609             ### lock the file ###
610 5 50       240 open(LOCK_FH, "${open_type}$file.lock") or croak "Can't open $file.lock: $!";
611 5         9 eval {
612 5 50       36 flock(LOCK_FH, $flock_type) or
613             croak "Can't lock ($lock_type, $open_type) $file.lock: $!";
614             };
615 5         16 undef $EVAL_ERROR; ### in case flock is not implemented ###
616             }
617              
618             ########################################################################
619             # Function: _unlock_datastore
620             # Description: Unlocks the datastore.
621             # Unlocks both types of locks, 'SHARED' and 'MUTEX'.
622             # Parameters: None.
623             # Returns: None.
624             ########################################################################
625              
626             sub _unlock_datastore {
627 5 50   5   13 (@_ > 0) or croak 'Usage: $obj->_unlock_datastore()';
628 5         6 my $this = shift;
629 5 50       10 ref($this) or croak "$this is not an object";
630              
631 5         13 $this->_trace();
632              
633             ### unlock the file ###
634 5         8 eval {
635 5         33 flock(LOCK_FH, LOCK_UN);
636             };
637 5         7 undef $EVAL_ERROR; ### in case flock is not implemented ###
638              
639 5         61 close(LOCK_FH);
640             }
641              
642             ### end of library ###
643             1;
644             __END__