Code

Updated acl listUpdated acl list
[gosa.git] / gosa-si / modules / DBsqlite.pm
index 5c9ae0c6f249fac2c7ab3d489b1b5b150c056e5f..985963da4a01e994e99d87dd0a858d8eef26fd9a 100644 (file)
@@ -2,58 +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.".si.lock";
-       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}, 9);
-       } 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;
 }
@@ -62,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}, 9);
+       &main::daemon_log("0 DEBUG: Released lock for database ".$self->{db_name}, 74);
+       $self->disconnect();
        return;
 }
 
@@ -86,16 +128,18 @@ sub create_table {
        my @col_names;
        my @col_names_creation;
        foreach my $col_name (@$col_names_ref) {
-               # Save full column description for creation of database
-               push(@col_names_creation, $col_name);
-               my @t = split(" ", $col_name);
-               my $column_name = $t[0];
-               # Save column name internally for select_dbentry
-               push(@col_names, $column_name);
+               push(@col_names, $col_name);
        }
-       
        $col_names->{ $table_name } = \@col_names;
-       my $col_names_string = join(", ", @col_names_creation);
+       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);
        
@@ -110,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;
@@ -179,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($@) {
@@ -193,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($@) {
@@ -208,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!", 9);
+                               &main::daemon_log("0 DEBUG: Execution of statement '$sql_statement' succeeded!", 74);
                                $success = 1;
                        };
                        if($@) {
@@ -238,6 +322,8 @@ sub add_dbentry {
 
        return 0;
 }
+
+
 sub update_dbentry {
        my ($self, $sql)= @_;
        if(not defined($self) or ref($self) ne 'GOSA::DBsqlite') {
@@ -270,15 +356,17 @@ sub get_table_columns {
        my @column_names;
 
        if(exists $col_names->{$table}) {
-               @column_names = @{$col_names->{$table}};
+               foreach my $col_name (@{$col_names->{$table}}) {
+                       push @column_names, ($1) if $col_name =~ /^(.*?)\s.*$/;
+               }
        } 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]);
                }
        }
-       return \@column_names;
 
+       return \@column_names;
 }
 
 
@@ -345,11 +433,11 @@ sub show_table {
 sub exec_statement {
        my $self = shift;
        my $sql_statement = 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;
        }
+
        if(not defined($sql_statement) or length($sql_statement) == 0) {
                &main::daemon_log("0 ERROR: GOSA::DBsqlite::exec_statement was called with empty statement!", 1);
                return;
@@ -366,36 +454,36 @@ 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) {
                $self->unlock();
                return \@db_answer ;
        }
-       
+
        # 2nd chance
        eval {
-               DBI->trace(6) if($main::verbose >= 7);
+               usleep(200);
                my $sth = $self->{dbh}->prepare($sql_statement);
                my $res = $sth->execute();
                @db_answer = @{$sth->fetchall_arrayref()};
                $sth->finish();
-               DBI->trace(0);
                $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");
                };
-               DBI->trace(0);
        }
        if($success) {
                $self->unlock();
@@ -404,13 +492,14 @@ sub exec_statement {
 
        # 3rd chance
        eval {
+               usleep(200);
                DBI->trace(6) if($main::verbose >= 7);
                my $sth = $self->{dbh}->prepare($sql_statement);
                my $res = $sth->execute();
                @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);