X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=gosa-si%2Fmodules%2FDBsqlite.pm;h=985963da4a01e994e99d87dd0a858d8eef26fd9a;hb=6a2030fa85791f8f789fb3bf549d99dfba833860;hp=84764fff2134b1b00fed13f0eed85f939afeba5d;hpb=f8ae5d1d124ad4d8ba706ee7b1d9d9485ce373f4;p=gosa.git diff --git a/gosa-si/modules/DBsqlite.pm b/gosa-si/modules/DBsqlite.pm index 84764fff2..985963da4 100644 --- a/gosa-si/modules/DBsqlite.pm +++ b/gosa-si/modules/DBsqlite.pm @@ -2,57 +2,99 @@ package GOSA::DBsqlite; use strict; use warnings; + use Carp; use DBI; -use Data::Dumper; use GOSA::GosaSupportDaemon; use Time::HiRes qw(usleep); +use Data::Dumper; use Fcntl qw/:DEFAULT :flock/; # import LOCK_* constants -my $col_names = {}; +our $col_names = {}; sub new { my $class = shift; my $db_name = shift; - my $lock = $db_name; + my $lock = $db_name.".si.lock"; my $self = {dbh=>undef,db_name=>undef,db_lock=>undef,db_lock_handle=>undef}; my $dbh = DBI->connect("dbi:SQLite:dbname=$db_name", "", "", {RaiseError => 1, AutoCommit => 1, PrintError => 0}); - my $sth = $dbh->prepare("pragma integrity_check"); - $sth->execute(); + + $self->{dbh} = $dbh; + $self->{db_name} = $db_name; + $self->{db_lock} = $lock; + bless($self,$class); + + my $sth = $self->{dbh}->prepare("pragma integrity_check"); + $sth->execute(); my @ret = $sth->fetchall_arrayref(); - $sth->finish(); + $sth->finish(); if(length(@ret)==1 && $ret[0][0][0] eq 'ok') { - &main::daemon_log("DEBUG: Database image $db_name is ok", 7); + &main::daemon_log("0 DEBUG: Database disk image '".$self->{db_name}."' is ok.", 74); } else { - &main::daemon_log("ERROR: Database image $db_name is malformed, creating new database.", 1); - $dbh->disconnect(); + &main::daemon_log("0 ERROR: Database disk image '".$self->{db_name}."' is malformed, creating new database!", 1); + $self->{dbh}->disconnect() or &main::daemon_log("0 ERROR: Could not disconnect from database '".$self->{db_name}."'!", 1); + $self->{dbh}= undef; unlink($db_name); - $dbh = DBI->connect("dbi:SQLite:dbname=$db_name", "", "", {RaiseError => 1, AutoCommit => 1}); } - $self->{dbh} = $dbh; - $self->{db_name} = $db_name; - $self->{db_lock} = $lock; - bless($self,$class); return($self); } +sub connect { + my $self = shift; + if(not defined($self) or ref($self) ne 'GOSA::DBsqlite') { + &main::daemon_log("0 ERROR: GOSA::DBsqlite::connect was called static! Argument was '$self'!", 1); + return; + } + + $self->{dbh} = DBI->connect("dbi:SQLite:dbname=".$self->{db_name}, "", "", {PrintError => 0, RaiseError => 1, AutoCommit => 1}) or + &main::daemon_log("0 ERROR: Could not connect to database '".$self->{db_name}."'!", 1); + + return; +} + + +sub disconnect { + my $self = shift; + if(not defined($self) or ref($self) ne 'GOSA::DBsqlite') { + &main::daemon_log("0 ERROR: GOSA::DBsqlite::disconnect was called static! Argument was '$self'!", 1); + return; + } + + eval { + $self->{dbh}->disconnect(); + }; + if($@) { + &main::daemon_log("ERROR: Could not disconnect from database '".$self->{db_name}."'!", 1); + } + + $self->{dbh}= undef; + + return; +} + + sub lock { my $self = shift; if(not defined($self) or ref($self) ne 'GOSA::DBsqlite') { - &main::daemon_log("0 ERROR: GOSA::DBsqlite::lock was called static! Statement was '$self'!", 1); + &main::daemon_log("0 ERROR: GOSA::DBsqlite::lock was called static! Argument was '$self'!", 1); return; } - if(not ref $self->{db_lock_handle}) { - sysopen($self->{db_lock_handle}, $self->{db_lock}, O_RDWR) or &main::daemon_log("0 ERROR: Opening the database ".$self->{db_name}." failed with $!", 1); + + if(not ref $self->{db_lock_handle} or not fileno $self->{db_lock_handle}) { + sysopen($self->{db_lock_handle}, $self->{db_lock}, O_RDWR | O_CREAT, 0600) or &main::daemon_log("0 ERROR: Opening the database ".$self->{db_name}." failed with $!", 1); } - my $lock_result = flock($self->{db_lock_handle}, LOCK_EX); - if($lock_result==1) { - seek($self->{db_lock_handle}, 0, 2); - &main::daemon_log("0 DEBUG: Acquired lock for database ".$self->{db_name}, 8); - } else { +get_lock: + my $lock_result = flock($self->{db_lock_handle}, LOCK_EX | LOCK_NB); + if(not $lock_result) { &main::daemon_log("0 ERROR: Could not acquire lock for database ".$self->{db_name}, 1); + usleep(250+rand(500)); + goto get_lock; + } else { + seek($self->{db_lock_handle}, 0, 2); + &main::daemon_log("0 DEBUG: Acquired lock for database ".$self->{db_name}, 74); + $self->connect(); } return; } @@ -61,14 +103,15 @@ sub lock { sub unlock { my $self = shift; if(not defined($self) or ref($self) ne 'GOSA::DBsqlite') { - &main::daemon_log("0 ERROR: GOSA::DBsqlite::unlock was called static! Statement was '$self'!", 1); + &main::daemon_log("0 ERROR: GOSA::DBsqlite::unlock was called static! Argument was '$self'!", 1); return; } if(not ref $self->{db_lock_handle}) { &main::daemon_log("0 BIG ERROR: Lockfile for database ".$self->{db_name}."got closed within critical section!", 1); } flock($self->{db_lock_handle}, LOCK_UN); - &main::daemon_log("0 DEBUG: Released lock for database ".$self->{db_name}, 8); + &main::daemon_log("0 DEBUG: Released lock for database ".$self->{db_name}, 74); + $self->disconnect(); return; } @@ -87,9 +130,16 @@ sub create_table { foreach my $col_name (@$col_names_ref) { push(@col_names, $col_name); } - $col_names->{ $table_name } = \@col_names; my $col_names_string = join(", ", @col_names); + + # Not activated yet + # Check schema + if($self->check_schema($table_name, $col_names_ref)) { + $self->exec_statement("DROP TABLE $table_name"); + &main::daemon_log("WARNING: Schema of table $table_name has changed! Table will be recreated!", 3); + } + my $sql_statement = "CREATE TABLE IF NOT EXISTS $table_name ( $col_names_string )"; my $res = $self->exec_statement($sql_statement); @@ -104,6 +154,46 @@ sub create_table { } +sub check_schema { + my $self = shift; + my $table_name = shift; + my $col_names_ref = shift; # ['id INTEGER PRIMARY KEY', 'timestamp VARCHAR(14) DEFAULT \'none\'', ... ] + my $col_names_length = @$col_names_ref; + + my $sql = "PRAGMA table_info($table_name)"; + my $res = $self->exec_statement($sql); # [ ['0', 'id', 'INTEGER', '0', undef, '1' ], ['1', 'timestamp', 'VARCHAR(14)', '0', '\'none\'', '0'], ... ] + my $db_table_length = @$res; + + # Tabel does not exists, so no differences + if ($db_table_length == 0) + { + return 0; + } + + + + # The number of columns is diffrent + if ($col_names_length != $db_table_length) + { + return 1; + } + + # The column name and column type to not match + for (my $i=0; $i < $db_table_length; $i++) + { + my @col_names_list = split(" ", @$col_names_ref[$i]); + if (($col_names_list[0] ne @{@$res[$i]}[1]) || ($col_names_list[1] ne @{@$res[$i]}[2])) + { + return 1; + } + } + + + return 0; +} + + + sub add_dbentry { my $self = shift; my $arg = shift; @@ -173,7 +263,7 @@ sub add_dbentry { my $sth = $self->{dbh}->prepare($sql_statement); $db_res = $sth->execute(); $sth->finish(); - &main::daemon_log("0 DEBUG: Execution of statement '$sql_statement' succeeded!", 9); + &main::daemon_log("0 DEBUG: Execution of statement '$sql_statement' succeeded!", 74); $success = 1; }; if($@) { @@ -187,7 +277,7 @@ sub add_dbentry { my $sth = $self->{dbh}->prepare($sql_statement); $db_res = $sth->execute(); $sth->finish(); - &main::daemon_log("0 DEBUG: Execution of statement '$sql_statement' succeeded!", 9); + &main::daemon_log("0 DEBUG: Execution of statement '$sql_statement' succeeded!", 74); $success = 1; }; if($@) { @@ -202,7 +292,7 @@ sub add_dbentry { my $sth = $self->{dbh}->prepare($sql_statement); $db_res = $sth->execute(); $sth->finish(); - &main::daemon_log("0 DEBUG: Execution of statement '$sql_statement' succeeded!", 7); + &main::daemon_log("0 DEBUG: Execution of statement '$sql_statement' succeeded!", 74); $success = 1; }; if($@) { @@ -271,7 +361,7 @@ sub get_table_columns { } } else { my @res; - foreach my $column ( $self->exec_statement ( "pragma table_info('$table')" ) ) { + foreach my $column ( @{ $self->exec_statement ( "pragma table_info('$table')" ) } ) { push(@column_names, @$column[1]); } } @@ -340,87 +430,6 @@ sub show_table { } -sub recreate_database { - my $self = shift; - if(not defined($self) or ref($self) ne 'GOSA::DBsqlite') { - &main::daemon_log("0 ERROR: GOSA::DBsqlite::exec_statement was called static! Statement was '$self'!", 1); - return; - } - - my $table_content; - - # Query all tables - eval { - my $sth = $self->{dbh}->prepare("select name from sqlite_master where type='table';"); - $sth->execute(); - my ($tables) = @{$sth->fetchall_arrayref()}; - foreach my $table (@$tables) { - if(defined($col_names->{$table})) { - # Schema definition for table exists, recreation is possible - my @column_names; - foreach my $column (@{$col_names->{$table}}) { - push @column_names, ($1) if $column =~ /(.*?)\s.*/; - } - my $column_query = join(',',@column_names); - my $sql = "SELECT $column_query FROM $table"; - my $sth = $self->{dbh}->prepare($sql); - $sth->execute(); - while (my @row = $sth->fetchrow_array()) { - push @{$table_content->{$table}}, @row; - } - $sth->finish; - } - } - - # Delete the database file - $self->{dbh}->disconnect(); - unlink($self->{db_name}); - - # Create a new database file - my $dbh = DBI->connect("dbi:SQLite:dbname=".$self->{db_name}, "", "", {RaiseError => 1, AutoCommit => 1}); - $self->{dbh} = $dbh; - - # Fill with contents - foreach my $table (@$tables) { - # Create schema - my $sql = "CREATE TABLE IF NOT EXISTS $table (".join(", ", @{$col_names->{$table}}).")"; - my $sth = $self->{dbh}->prepare($sql); - $sth->execute(); - - # Insert Dump - if(defined($table_content->{$table})) { - &main::daemon_log("0 DEBUG: Filling table ".$self->{db_name}.".$table with dump.", 7); - my %insert_hash; - my $i=0; - foreach my $row ($table_content->{$table}) { - foreach my $column (@{$col_names->{$table}}) { - my $column_name = $1 if $column =~ /(.*?)\s.*/; - $insert_hash{$column_name} = defined(@$row[$i])?@$row[$i]:undef; - $i++; - } - my @values; - my $column_query = join(",",keys %insert_hash); - foreach my $column(keys %insert_hash) { - push @values, $insert_hash{$column}; - } - my $value_query = join("', '", @values); - my $sql = "INSERT INTO $table ($column_query) VALUES ('$value_query')"; - my $sth = $self->{dbh}->prepare($sql); - $sth->execute; - } - } else { - &main::daemon_log("0 DEBUG: Table ".$self->{db_name}.".$table was empty.", 7); - } - } - }; - if($@) { - print STDERR Dumper($@); - } - - return; -} - - sub exec_statement { my $self = shift; my $sql_statement = shift; @@ -445,12 +454,13 @@ sub exec_statement { @db_answer = @{$sth->fetchall_arrayref()}; $sth->finish(); $success=1; - &main::daemon_log("0 DEBUG: $sql_statement succeeded.", 9); + &main::daemon_log("0 DEBUG: $sql_statement succeeded.", 74); }; if($@) { eval { $self->{dbh}->do("ANALYZE"); $self->{dbh}->do("VACUUM"); + $self->{dbh}->do("pragma integrity_check"); }; } if($success) { @@ -466,10 +476,14 @@ sub exec_statement { @db_answer = @{$sth->fetchall_arrayref()}; $sth->finish(); $success=1; - &main::daemon_log("0 DEBUG: $sql_statement succeeded.", 9); + &main::daemon_log("0 DEBUG: $sql_statement succeeded.", 74); }; if($@) { - $self->recreate_database(); + eval { + $self->{dbh}->do("ANALYZE"); + $self->{dbh}->do("VACUUM"); + $self->{dbh}->do("pragma integrity_check"); + }; } if($success) { $self->unlock(); @@ -485,7 +499,7 @@ sub exec_statement { @db_answer = @{$sth->fetchall_arrayref()}; $sth->finish(); DBI->trace(0); - &main::daemon_log("0 DEBUG: $sql_statement succeeded.", 9); + &main::daemon_log("0 DEBUG: $sql_statement succeeded.", 74); }; if($@) { DBI->trace(0);