summaryrefslogblamecommitdiffstats
path: root/config-db/OpenSLX/MetaDB/CSV.pm
blob: fbd2c7ecb7db1c8d578b5b6c5a2a66330825c930 (plain) (tree)
1
2
3
4
5
6
7
8
                                         
 

                                                                    
 

                                                                         
 




                                                                               
                             
 
           

             
                                  




                                                                                
                                                                                
                                                                                
                              
                  
                    
 





                                                                                
                       


                                   
                                                              


                         
                                               

                                                           
                                                                     


                                                                 
                                                      
         
                                                               


                                                                                    
               


         

                                                                               
                         
                         




                                 
                     
                                                           

                         
                                      
                                                          
                                                       
                                                                                

                                                 
                                                                                
               


                      
                            


                                                   
                                                              






                                            
                            


                                                   
                                                              





                                            
                          

                                                                        



                                       
                                                       
                                    
                                                 
                                                  
                                                                     
                              
                                                                     



                                                                              



                                                                                       

                                                                                     
                                    
                                     

                          
                                                                        
                           
                                                                         
                                
                                                                       





                       


                                                                 


                                 
                                                                      
               


                     

                                                                






                                                                              
               


                   

                                                                




                                                  
               

 
  
# Copyright (c) 2006, 2007 - OpenSLX GmbH
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
#
# If you have any feedback please consult http://openslx.org/feedback and
# send your suggestions, praise, or complaints to feedback@openslx.org
#
# General information about OpenSLX can be found at http://openslx.org/
# -----------------------------------------------------------------------------
# CSV.pm
#	- provides CSV-specific overrides of the OpenSLX MetaDB API.
# -----------------------------------------------------------------------------
package OpenSLX::MetaDB::CSV;

use strict;
use warnings;

use base qw(OpenSLX::MetaDB::DBI);

################################################################################
### This class provides a MetaDB backend for CSV files (CSV = comma separated
### files).
### - each table will be stored into a CSV file.
### - by default all files will be created inside a 'openslxdata-csv' directory.
################################################################################
use Fcntl qw(:DEFAULT :flock);
use DBD::CSV 0.22;
use OpenSLX::Basics;

################################################################################
### implementation
################################################################################
sub new
{
	my $class = shift;
	my $self  = {};
	return bless $self, $class;
}

sub connect		## no critic (ProhibitBuiltinHomonyms)
{
	my $self = shift;

	my $dbSpec = $openslxConfig{'db-spec'};
	if (!defined $dbSpec) {
		# build $dbSpec from individual parameters:
		my $dbBasepath = "$openslxConfig{'private-path'}/db";
		my $dbDatadir  = "$openslxConfig{'db-name'}-csv";
		my $dbPath     = "$dbBasepath/$dbDatadir";
		system("mkdir -p $dbPath") unless -e $dbPath;
		$dbSpec = "f_dir=$dbPath;csv_eol=\n;";
	}
	vlog(1, "trying to connect to CSV-database <$dbSpec>");
	$self->{'dbh'} =
	  DBI->connect("dbi:CSV:$dbSpec", undef, undef, {PrintError => 0})
	  or die _tr("Cannot connect to database '%s' (%s)", $dbSpec, $DBI::errstr);
	return;
}

sub quote
{    # DBD::CSV has a buggy quoting mechanism which can't cope with backslashes
	    # so we reimplement the quoting ourselves...
	my $self = shift;
	my $val  = shift;

	$val =~ s[(['])][\\$1]go;
	return "'$val'";
}

sub start_transaction
{       # simulate a global transaction by flocking a file:
	my $self = shift;

	my $dbh      = $self->{'dbh'};
	my $lockFile = "$dbh->{'f_dir'}/transaction-lock";
	sysopen(TRANSFILE, $lockFile, O_RDWR | O_CREAT)
	  or croak _tr(q[Can't open transaction-file '%s' (%s)], $lockFile, $!);
	$self->{"transaction-lock"} = *TRANSFILE;
	flock(TRANSFILE, LOCK_EX)
	  or croak _tr(q[Can't lock transaction-file '%s' (%s)], $lockFile, $!);
	return;
}

sub commit_transaction
{    # free transaction-lock
	my $self = shift;

	if (!defined $self->{"transaction-lock"}) {
		croak _tr(q[no open transaction-lock found!]);
	}
	close($self->{"transaction-lock"});
	$self->{"transaction-lock"} = undef;
	return 1;
}

sub rollback_transaction
{    # free transaction-lock
	my $self = shift;

	if (!defined $self->{"transaction-lock"}) {
		croak _tr(q[no open transaction-lock found!]);
	}
	close($self->{"transaction-lock"});
	$self->{"transaction-lock"} = undef;
	return 1;
}

sub generateNextIdForTable
{    # CSV doesn't provide any mechanism to generate IDs, we provide one
	my $self  = shift;
	my $table = shift;

	return 1 unless defined $table;

	# fetch the next ID from a table-specific file:
	my $dbh    = $self->{'dbh'};
	my $idFile = "$dbh->{'f_dir'}/id-$table";
	sysopen(IDFILE, $idFile, O_RDWR | O_CREAT)
	  or croak _tr(q[Can't open ID-file '%s' (%s)], $idFile, $!);
	flock(IDFILE, LOCK_EX)
	  or croak _tr(q[Can't lock ID-file '%s' (%s)], $idFile, $!);
	my $nextID = <IDFILE>;
	if (!$nextID) {
		# no ID information available, we protect against users having
		# deleted the ID-file by fetching the highest ID from the DB:
		#
		# N.B.: older versions of DBD::CSV (notably the one that comes with
		#       SUSE-9.3) do not understand the max() function, so we determine
		#       the maximum ID manually:
		my @IDs =
		  sort { $b <=> $a } $self->_doSelect("SELECT id FROM $table", 'id');
		my $maxID = $IDs[0];
		$nextID = 1 + $maxID;
	}
	seek(IDFILE, 0, 0)
	  or croak _tr(q[Can't to seek ID-file '%s' (%s)], $idFile, $!);
	truncate(IDFILE, 0)
	  or croak _tr(q[Can't truncate ID-file '%s' (%s)], $idFile, $!);
	print IDFILE $nextID + 1
	  or croak _tr(q[Can't update ID-file '%s' (%s)], $idFile, $!);
	close(IDFILE);

	return $nextID;
}

sub schemaDeclareTable
{    # explicitly set file name for each table such that it makes
	    # use of '.csv'-extension
	my $self  = shift;
	my $table = shift;

	my $dbh = $self->{'dbh'};
	$dbh->{'csv_tables'}->{"$table"} = {'file' => "${table}.csv"};
	return;
}

sub schemaRenameTable
{       # renames corresponding id-file after renaming the table
	my $self     = shift;
	my $oldTable = shift;
	my $newTable = shift;

	$self->schemaDeclareTable($newTable);
	$self->SUPER::schemaRenameTable($oldTable, $newTable, @_);
	my $dbh = $self->{'dbh'};
	rename "$dbh->{'f_dir'}/id-$oldTable", "$dbh->{'f_dir'}/id-$newTable";
	return;
}

sub schemaDropTable
{       # removes corresponding id-file after dropping the table
	my $self  = shift;
	my $table = shift;

	$self->SUPER::schemaDropTable($table, @_);
	my $dbh = $self->{'dbh'};
	unlink "$dbh->{'f_dir'}/id-$table";
	return;
}

1;