Deleting Data

The final form of data manipulation that you can apply to flat-file databases is the removal, or deletion, of records from the database. We shall process the file a record at a time by passing the data through a temporary file, just as we did for updating, rather than slurping all the data into memory and dumping it at the end.

With this technique, the action of removing a record from the database is more an act of omission than any actual deletion. Each record is read in from the file, tested, and written out to the file. When the record to be deleted is encountered, it is simply not written to the temporary file. This effectively removes all trace of it from the database, albeit in a rather unsophisticated way.

The following program can be used to remove the relevant record from the delimited megalithic database when given an argument of the name of the site to delete:

#!/usr/bin/perl -w
#
# ch02/deletemegadata/deletemegadata: Deletes the record for the given
#                                     megalithic site. Uses
#                                     colon-separated data
#

### Check the user has supplied an argument to scan for
###     1) The name of the file containing the data
###     2) The name of the site to delete
die "Usage: deletemegadata <data file> <site name>\n"
    unless @ARGV == 2;

my $megalithFile  = $ARGV[0];
my $siteName      = $ARGV[1];
my $tempFile      = "tmp.$$";

### Open the data file for reading, and die upon failure
open MEGADATA, "<$megalithFile"
    or die "Can't open $megalithFile: $!\n";

### Open the temporary megalith data file for writing
open TMPMEGADATA, ">$tempFile"
    or die "Can't open temporary file $tempFile: $!\n";

### Scan through all the entries for the desired site
while ( <MEGADATA> ) {

    ### Extract the site name (the first field) from the record
    my ( $name ) = split( /:/, $_ );
    
    ### Test the sitename against the record's name
    if ( $siteName eq $name ) {
    
        ### We've found the record to delete, so skip it and move to next record
        next;
    }
    
    ### Write the original record out to the temporary file
    print TMPMEGADATA $_
        or die "Error writing $tempFile: $!\n";
    }

### Close the megalith input data file
close MEGADATA;

### Close the temporary megalith output data file
close TMPMEGADATA
    or die "Error closing $tempFile: $!\n";

### We now "commit" the changes by deleting the old file ...
unlink $megalithFile
    or die "Can't delete old $megalithFile: $!\n";

### and renaming the new file to replace the old one.
rename $tempFile, $megalithFile
    or die "Can't rename '$tempFile' to '$megalithFile': $!\n";

exit 0;

The code to remove records from a fixed-length data file is almost identical. The only change is in the code to extract the field value, as you’d expect:

### Extract the site name (the first field) from the record
my ( $name ) = unpack( "A64", $_ );

Like updating, deleting data may cause problems if multiple users are attempting to make simultaneous changes to the data. We’ll look at how to deal with this problem a little later in this chapter.