- add database functionality
authorAndreas Scherbaum <andreas@scherbaum.biz>
Mon, 27 Feb 2012 00:01:24 +0000 (01:01 +0100)
committerAndreas Scherbaum <andreas@scherbaum.biz>
Mon, 27 Feb 2012 00:01:24 +0000 (01:01 +0100)
- almost full rewrite of db.pm
- open database connection in docbot
- test connection and configuration, add db ping

db.pm
docbot.pl

diff --git a/db.pm b/db.pm
index 38d6a68e38df55949bca3c49eacd4b1cc9061bb9..580d8384dae4588ce520abc070c58bbed6b7589a 100644 (file)
--- a/db.pm
+++ b/db.pm
@@ -29,6 +29,7 @@ use constant INFO   => 0;
 #  - pointer to config class
 sub new {
     my $class = shift;
+
     my $self = {};
     # bless mysqlf
     bless($self, $class);
@@ -36,41 +37,107 @@ sub new {
     # define own variables
     # db connection
     $self->{db_connection} = undef;
+    # configuration data
+    $self->{config} = {};
 
     # return reference
     return $self;
 }
 
 
-# DESTROY()
+# set_config()
 #
-# destructor
+# set a configuration parameter
 #
 # parameter:
-#  - self
+#  - class name ($self)
+#  - key name
+#  - value name
 # return:
 #  none
-sub DESTROY {
+sub set_config {
     my $self = shift;
+    my $key = shift;
+    my $value = shift;
+
+    $self->{config}->{$key} = $value;
+}
+
+
+# verify_config()
+#
+# verify database connection (if all required parameters are set)
+#
+# parameter:
+#  - class name ($self)
+# return:
+#  - 0/1
+sub verify_config {
+    my $self = shift;
+
+    if (!defined($self->{config}->{'name'})) {
+        return 0;
+    }
+    if (!defined($self->{config}->{'host'})) {
+        return 0;
+    }
+    if (!defined($self->{config}->{'port'})) {
+        return 0;
+    }
+    if (!defined($self->{config}->{'username'})) {
+        return 0;
+    }
+    if (!defined($self->{config}->{'password'})) {
+        return 0;
+    }
+    if (!defined($self->{config}->{'schema'})) {
+        return 0;
+    }
 
+    return 1;
 }
 
 
+# open_db_connection()
+#
+# open database connection
+#
+# parameter:
+#  - class name ($self)
+# return:
+#  - 0/1
 sub open_db_connection {
     my $self = shift;
 
-    my $DSN = "dbi:Pg:dbname=$main::db_name";
-    if ($main::db_host) {
-      $DSN .= ";host=$main::db_host";
+    if (!$self->verify_config()) {
+        return 0;
     }
-    if ($main::db_port) {
-      $DSN .= ";port=$main::db_port";
+
+    if ($self->{db_connection}) {
+        # Note: do not try to ping the database here, this will create an endless loop
+        return 1;
+    }
+
+    my $db_name = $self->{config}->{'name'};
+    my $db_host = $self->{config}->{'host'};
+    my $db_port = $self->{config}->{'port'};
+    my $db_username = $self->{config}->{'username'};
+    my $db_password = $self->{config}->{'password'};
+    my $db_schema = $self->{config}->{'schema'};
+
+
+    my $DSN = "dbi:Pg:dbname=$db_name";
+    if ($db_host) {
+      $DSN .= ";host=$db_host";
+    }
+    if ($db_port) {
+      $DSN .= ";port=$db_port";
     }
 
     my $dbh = DBI->connect_cached(
         $DSN,
-        $main::db_user,
-        $main::db_pass,
+        $db_username,
+        $db_password,
         {
             "RaiseError" => 0,
             "PrintError" => 0,
@@ -79,22 +146,182 @@ sub open_db_connection {
     );
 
     unless ($dbh) {
-        print_msg("Can't connect to database - $DBI::errstr\n", ERROR);
+        main::print_msg("Can't connect to database - $DBI::errstr\n", ERROR);
         return 0;
     }
 
     $dbh->{RaiseError} = 1;
 
-    if ($main::db_schema) {
-        $dbh->do("SET search_path = '$main::db_schema'");
+    if ($db_schema) {
+        $dbh->do("SET search_path = '$db_schema'");
         $dbh->commit();
     }
 
     $self->{db_connection} = $dbh;
+    $main::statistics{'database_connects'}++;
+
+    return 1;
+}
+
+
+# reconnect_db_connection()
+#
+# reconnect the database connection
+#
+# parameter:
+#  - class name ($self)
+# return:
+#  - 0/1
+sub reconnect_db_connection {
+    my $self = shift;
+
+    $self->close_db_connection();
+    if (!$self->open_db_connection()) {
+        return 0;
+    }
+
+    return 1;
+}
+
+
+# close_db_connection()
+#
+# close database connection
+#
+# parameter:
+#  - class name ($self)
+# return:
+#  none
+sub close_db_connection {
+    my $self = shift;
+
+    if (defined($self->{db_connection})) {
+        $self->{db_connection}->disconnect;
+        undef($self->{db_connection});
+    }
+}
+
+
+# test_database()
+#
+# test database connectivity
+#
+# parameter:
+#  - class name ($self)
+# return:
+#  - 0/1
+sub test_database {
+    my $self = shift;
+
+    if (!$self->ping()) {
+        return 0;
+    }
+
+    return 1;
+}
+
+
+# ping()
+#
+# execute a test query
+#
+# parameter:
+#  - class name ($self)
+# return:
+#  - 0/1
+sub ping {
+    my $self = shift;
+
+    my $query = 'SELECT 1';
+    if (!$self->do($query)) {
+        # ping failed, reconnect the database
+        $self->reconnect_db_connection();
+        if (!$self->do($query)) {
+            # reconnect failed
+            return 0;
+        }
+    }
 
     return 1;
 }
 
 
+# do()
+#
+# execute a query
+#
+# parameter:
+#  - class name ($self)
+#  - query
+# return:
+#  - 0/1
+sub do {
+    my $self = shift;
+    my $query = shift;
+
+    main::print_msg("Execute database query: $query", DEBUG2);
+
+    if (!defined($self->{db_connection})) {
+        main::print_msg("Database not connected", ERROR);
+        return 0;
+    }
+
+    my $result = $self->{db_connection}->do($query);
+    if (!$result) {
+        main::print_msg("Could not execute database query", ERROR);
+        return 0;
+    }
+    $main::statistics{'database_queries'}++;
+
+    return 1;
+}
+
+
+# query()
+#
+# execute a query and return the result set
+#
+# parameter:
+#  - class name ($self)
+#  - query
+# return:
+#  - pointer to query result, or undef
+sub query {
+    my $self = shift;
+    my $query = shift;
+
+    main::print_msg("Execute database query: $query", DEBUG2);
+
+    if (!defined($self->{db_connection})) {
+        main::print_msg("Database not connected", ERROR);
+        return undef;
+    }
+
+    my $st = $self->{db_connection}->prepare($query);
+    if (!$st->execute) {
+        main::print_msg("Could not execute database query", ERROR);
+        return undef;
+    }
+    $main::statistics{'database_queries'}++;
+
+    return $st;
+}
+
+
+# DESTROY()
+#
+# destructor
+#
+# parameter:
+#  - self
+# return:
+#  none
+sub DESTROY {
+    my $self = shift;
+
+    $self->close_db_connection();
+}
+
+
 # finish module
 1;
index 28437ca31ca6c88e71cd9c3957e7c03a5ce4e40d..5520ad2f8fefa7d0ab2a052878b972105ad1d16e 100755 (executable)
--- a/docbot.pl
+++ b/docbot.pl
@@ -128,6 +128,7 @@ if (length($main::config_file) > 0) {
 }
 
 
+init_database();
 init_sessions();
 
 
@@ -294,10 +295,44 @@ sub init_statistics {
     $main::statistics{'database_queries'} = 0;
 
     $main::statistics{'connects'} = 0;
-
 }
 
 
+# init_database()
+#
+# init configuration
+#
+# parameter:
+#  none
+# return:
+#  none
+sub init_database {
+    print_msg("Init database configuration and connection", DEBUG);
+
+    # create database class
+    $main::db = docbot::db->new();
+    # fill in the configuration
+    $main::db->set_config('name', config_get_key2('database', 'name'));
+    $main::db->set_config('host', config_get_key2('database', 'host'));
+    $main::db->set_config('port', (config_get_key2('database', 'port')) ? config_get_key2('database', 'port') : '5432');
+    $main::db->set_config('username', config_get_key2('database', 'username'));
+    $main::db->set_config('password', config_get_key2('database', 'password'));
+    $main::db->set_config('schema', (config_get_key2('database', 'schema')) ? config_get_key2('database', 'schema') : 'public');
+
+    # validate formal database configuration
+    if (!$main::db->verify_config()) {
+        die("Database configuration is incomplete!\n");
+    }
+    # open database connection
+    if (!$main::db->open_db_connection()) {
+        die("Could not open database connection!\n");
+    }
+    # and test connectivity
+    if (!$main::db->test_database()) {
+        die("Could not test database connection!\n");
+    }
+}
+
 
 # init_config()
 #
@@ -849,7 +884,7 @@ BEGIN {
 # return:
 #  none
 sub maintenance {
-    if (!test_database()) {
+    if (!$main::db->test_database()) {
         print_msg("Database not connected!", ERROR);
     }