]> git.donarmstrong.com Git - infobot.git/commitdiff
add initial SQLite support
authortimriker <timriker@c11ca15a-4712-0410-83d8-924469b57eb5>
Sun, 3 Nov 2002 05:21:01 +0000 (05:21 +0000)
committertimriker <timriker@c11ca15a-4712-0410-83d8-924469b57eb5>
Sun, 3 Nov 2002 05:21:01 +0000 (05:21 +0000)
git-svn-id: https://svn.code.sf.net/p/infobot/code/trunk/blootbot@595 c11ca15a-4712-0410-83d8-924469b57eb5

.cvsignore
INSTALL
INSTALL.dbm
INSTALL.sqlite [new file with mode: 0644]
files/sample/sample.config.broken
src/IRC/Schedulers.pl
src/Modules/Countdown.pl
src/Modules/UserDCC.pl
src/Process.pl
src/db_sqlite.pl [new file with mode: 0644]
src/modules.pl

index 357cc01f1b11079c093043112282b415f3e5b439..e74fd0a3610cc470d77e6553dd7d03cc96197938 100644 (file)
@@ -1,3 +1,4 @@
 blootbot-*
 blootbot.pid
+blootbot.sqlite
 Temp
diff --git a/INSTALL b/INSTALL
index a85aaa16ecca134b0ec0d36a3bd01a49b58df19f..8ab833600b9fc271037ee84df525c19c9782881a 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -21,6 +21,7 @@ Method of installation.
 
 - Choose your database:
        - MySQL, read INSTALL.mysql (supported)
+       - SQLite, read INSTALL.sqlite (unsupported, may work)
        - PgSQL, read INSTALL.pgsql (unsupported, may work)
        - Berkeley DBM, read INSTALL.dbm (unsupported, may work)
 
index 93b3db674de38deef95a34a54686ee9ffd273a41..02d9c4c17512c344486b1d40e4b030d2ada9b43d 100644 (file)
@@ -7,7 +7,7 @@ INSTALLATION of dbm
 - If the bot crashes, the dbm file may increase in size dramatically, from
   900k-1400k to 16m-24m
 - dbm is a slow but simple form of db.  If you want performance, try mysql
-  or pgsql (NOT YET)
+  or sqlite (NOT SUPPORTED) or pgsql (NOT YET)
 
 = To convert dbm file to mysql table:
        - run 'scripts/dbm2mysql.pl old-db' to convert dbm database file
diff --git a/INSTALL.sqlite b/INSTALL.sqlite
new file mode 100644 (file)
index 0000000..a216df2
--- /dev/null
@@ -0,0 +1,5 @@
+INSTALL.sqlite
+----------------
+
+- Install SQLite libraries and DBI Perl modules.
+       - Debian: (apt-get install libsqlite0 libdbd-sqlite-perl)
index d5b43e9df541de2ce1082cfef801938f0309c316..d43fa1cbcc1e96bcbcedbea7830f91916a2f5a0f 100644 (file)
@@ -45,6 +45,7 @@ set maxLogSize                10000000
 # [str] Ability to remember/tell factoids
 #      none    -- disable.
 #      mysql   -- MySQL
+#      sqlite  -- SQLite (libdbd-sqlite-perl)
 #      pgsql   -- PostGreSQL (NOT SUPPORTED YET)
 #      dbm     -- Berkeley DBM
 ### REQUIRED by factoids,freshmeat,karma,seen,...
index 9c5bbeda5409c2b045f0601ff120b5096504abb0..c0c9cf2ef857bf56211f7e78e12eb63b36e315c1 100644 (file)
@@ -243,10 +243,10 @@ sub seenFlushOld {
     my $max_time = &getChanConfDefault("seenMaxDays", 30) *60*60*24;
     my $delete   = 0;
 
-    if ($param{'DBType'} =~ /^pgsql|mysql/i) {
+    if ($param{'DBType'} =~ /^pgsql|mysql|sqlite/i) {
        my $query;
 
-       if ($param{'DBType'} =~ /^mysql$/i) {
+       if ($param{'DBType'} =~ /^mysql|sqlite$/i) {
            $query = "SELECT nick,time FROM seen GROUP BY nick HAVING ".
                        "UNIX_TIMESTAMP() - time > $max_time";
        } else {        # pgsql.
@@ -547,7 +547,7 @@ sub seenFlush {
     $stats{'new'}      = 0;
     $stats{'old'}      = 0;
 
-    if ($param{'DBType'} =~ /^(mysql|pgsql)$/i) {
+    if ($param{'DBType'} =~ /^(mysql|pgsql|sqlite)$/i) {
        foreach $nick (keys %seencache) {
            my $retval = &dbReplace("seen", "nick", (
                        "nick" => lc $seencache{$nick}{'nick'},
index e805d8e8d236278c8d7be77564a5e123d3061b24..b29447783157df46461c49a8b987eb100433866a 100644 (file)
@@ -44,7 +44,7 @@ sub Countdown {
        ### SQL SPECIFIC.
        my ($to_days,$dayname,$monname);
 
-       if ($param{'DBType'} =~ /^mysql$/i) {
+       if ($param{'DBType'} =~ /^mysql|sqlite$/i) {
            $to_days = (&dbRawReturn("SELECT TO_DAYS(NOW()) - TO_DAYS('$sqldate')"))[0];
            $dayname = (&dbRawReturn("SELECT DAYNAME('$sqldate')"))[0];
            $monname = (&dbRawReturn("SELECT MONTHNAME('$sqldate')"))[0];
index 578cbc72a1f0ae94c1f1587f81ec135d0b1047b1..8bd29dbdbc739bcc875f4b3ef55c4b0844f5969a 100644 (file)
@@ -358,7 +358,7 @@ sub userDCC {
            return;
        }
 
-       ### TODO: fix up $op to support mysql/pgsql/dbm(perl)
+       ### TODO: fix up $op to support mysql/sqlite/pgsql/dbm(perl)
        ### TODO: => add db/sql specific function to fix this.
        my @list = &searchTable("factoids", "factoid_key",
                        "factoid_value", $op);
index cbdb6cabbf4dca06e6087781745b1b1ce490efa4..d4473b414dd98c44ebea2723a5a411f740f231d3 100644 (file)
@@ -338,7 +338,7 @@ sub process {
        }
     }
 
-    if (&IsParam("factoids") and $param{'DBType'} =~ /^(mysql|pgsql|dbm)/i) {
+    if (&IsParam("factoids") and $param{'DBType'} =~ /^(mysql|sqlite|pgsql|dbm)/i) {
        &FactoidStuff();
     } elsif ($param{'DBType'} =~ /^none$/i) {
        return "NO FACTOIDS.";
diff --git a/src/db_sqlite.pl b/src/db_sqlite.pl
new file mode 100644 (file)
index 0000000..6b77aa5
--- /dev/null
@@ -0,0 +1,534 @@
+#
+# db_sqlite.pl: SQLite database frontend.
+#      Author: Tim Riker <Tim@Rikers.org>
+#     Version: 0.1 (20021101)
+#     Created: 20021101
+#
+
+package main;
+eval "use DBI";
+
+if (&IsParam("useStrict")) { use strict; }
+
+#####
+# &openDB($dbname, $sqluser, $sqlpass, $nofail);
+sub openDB {
+    my ($db, $user, $pass, $no_fail) = @_;
+    my $dsn = "DBI:SQLite:dbname=$db.sqlite";
+    $dbh = DBI->connect($dsn,$user,$pass);
+
+    if ($dbh) {
+       &status("Opened SQLite connection $dsn");
+    } else {
+       &ERROR("cannot connect $dsn.");
+       &ERROR("since SQLite is not available, shutting down bot!");
+       &closePID();
+       &closeSHM($shm);
+       &closeLog();
+
+       return if ($no_fail);
+
+       exit 1;
+    }
+}
+
+sub closeDB {
+    return 0 unless ($dbh);
+
+    my $hoststr = "";
+    $hoststr = " to $param{'SQLHost'}" if (exists $param{'SQLHost'});
+
+    &status("Closed SQLite connection$hoststr.");
+    $dbh->disconnect();
+
+    return 1;
+}
+
+#####
+# Usage: &dbQuote($str);
+sub dbQuote {
+    return $dbh->quote($_[0]);
+}
+
+#####
+# Usage: &dbGet($table, $select, $where);
+sub dbGet {
+    my ($table, $select, $where) = @_;
+    my $query  = "SELECT $select FROM $table";
+    $query     .= " WHERE $where" if ($where);
+
+    if (!defined $select or $select =~ /^\s*$/) {
+       &WARN("dbGet: select == NULL.");
+       return;
+    }
+
+    if (!defined $table or $table =~ /^\s*$/) {
+       &WARN("dbGet: table == NULL.");
+       return;
+    }
+
+    my $sth;
+    if (!($sth = $dbh->prepare($query))) {
+       &ERROR("Get: prepare: $DBI::errstr");
+       return;
+    }
+
+    &SQLDebug($query);
+    if (!$sth->execute) {
+       &ERROR("Get: execute: '$query'");
+       $sth->finish;
+       return 0;
+    }
+
+    my @retval = $sth->fetchrow_array;
+
+    $sth->finish;
+
+    if (scalar @retval > 1) {
+       return @retval;
+    } elsif (scalar @retval == 1) {
+       return $retval[0];
+    } else {
+       return;
+    }
+}
+
+#####
+# Usage: &dbGetCol($table, $select, $where, [$type]);
+sub dbGetCol {
+    my ($table, $select, $where, $type) = @_;
+    my $query  = "SELECT $select FROM $table";
+    $query     .= " WHERE ".$where if ($where);
+    my %retval;
+
+    my $sth = $dbh->prepare($query);
+    &SQLDebug($query);
+    if (!$sth->execute) {
+       &ERROR("GetCol: execute: '$query'");
+       $sth->finish;
+       return;
+    }
+
+    if (defined $type and $type == 2) {
+       &DEBUG("dbgetcol: type 2!");
+       while (my @row = $sth->fetchrow_array) {
+           $retval{$row[0]} = join(':', $row[1..$#row]);
+       }
+       &DEBUG("dbgetcol: count => ".scalar(keys %retval) );
+
+    } elsif (defined $type and $type == 1) {
+       while (my @row = $sth->fetchrow_array) {
+           # reverse it to make it easier to count.
+           if (scalar @row == 2) {
+               $retval{$row[1]}{$row[0]} = 1;
+           } elsif (scalar @row == 3) {
+               $retval{$row[1]}{$row[0]} = 1;
+           }
+           # what to do if there's only one or more than 3?
+       }
+
+    } else {
+       while (my @row = $sth->fetchrow_array) {
+           $retval{$row[0]} = $row[1];
+       }
+    }
+
+    $sth->finish;
+
+    return %retval;
+}
+
+#####
+# Usage: &dbGetColNiceHash($table, $select, $where);
+sub dbGetColNiceHash {
+    my ($table, $select, $where) = @_;
+    $select    ||= "*";
+    my $query  = "SELECT $select FROM $table";
+    $query     .= " WHERE ".$where if ($where);
+    my %retval;
+
+    my $sth = $dbh->prepare($query);
+    &SQLDebug($query);
+    if (!$sth->execute) {
+       &ERROR("GetColNiceHash: execute: '$query'");
+#      &ERROR("GetCol => $DBI::errstr");
+       $sth->finish;
+       return;
+    }
+
+    %retval = %{ $sth->fetchrow_hashref() };
+
+    $sth->finish;
+
+    return %retval;
+}
+
+####
+# Usage: &dbGetColInfo($table);
+sub dbGetColInfo {
+    my ($table) = @_;
+
+    my $query = "SHOW COLUMNS from $table";
+    my %retval;
+
+    my $sth = $dbh->prepare($query);
+    &SQLDebug($query);
+    if (!$sth->execute) {
+       &ERROR("GRI => '$query'");
+       &ERROR("GRI => $DBI::errstr");
+       $sth->finish;
+       return;
+    }
+
+    my @cols;
+    while (my @row = $sth->fetchrow_array) {
+       push(@cols, $row[0]);
+    }
+    $sth->finish;
+
+    return @cols;
+}
+
+#####
+# Usage: &dbSet($table, $primhash_ref, $hash_ref);
+#  Note: dbSet does dbQuote.
+sub dbSet {
+    my ($table, $phref, $href) = @_;
+    my $where = join(' AND ', map {
+               $_."=".&dbQuote($phref->{$_})
+       } keys %{$phref}
+    );
+
+    if (!defined $phref) {
+       &WARN("dbset: phref == NULL.");
+       return;
+    }
+
+    if (!defined $href) {
+       &WARN("dbset: href == NULL.");
+       return;
+    }
+
+    if (!defined $table) {
+       &WARN("dbset: table == NULL.");
+       return;
+    }
+
+    my $result = &dbGet($table, join(',', keys %{$phref}), $where);
+
+    my(@keys,@vals);
+    foreach (keys %{$href}) {
+       push(@keys, $_);
+       push(@vals, &dbQuote($href->{$_}) );
+    }
+
+    if (!@keys or !@vals) {
+       &WARN("dbset: keys or vals is NULL.");
+       return;
+    }
+
+    my $query;
+    if (defined $result) {
+       my @keyval;
+       for(my$i=0; $i<scalar @keys; $i++) {
+           push(@keyval, $keys[$i]."=".$vals[$i] );
+       }
+
+       $query = "UPDATE $table SET ".
+               join(' AND ', @keyval).
+               " WHERE ".$where;
+    } else {
+       foreach (keys %{$phref}) {
+           push(@keys, $_);
+           push(@vals, &dbQuote($phref->{$_}) );
+       }
+
+       $query = sprintf("INSERT INTO $table (%s) VALUES (%s)",
+               join(',',@keys), join(',',@vals) );
+    }
+
+    &dbRaw("Set", $query);
+
+    return 1;
+}
+
+#####
+# Usage: &dbUpdate($table, $primkey, $primval, %hash);
+#  Note: dbUpdate does dbQuote.
+sub dbUpdate {
+    my ($table, $primkey, $primval, %hash) = @_;
+    my (@array);
+
+    foreach (keys %hash) {
+       push(@array, "$_=".&dbQuote($hash{$_}) );
+    }
+
+    &dbRaw("Update", "UPDATE $table SET ".join(', ', @array).
+               " WHERE $primkey=".&dbQuote($primval)
+    );
+
+    return 1;
+}
+
+#####
+# Usage: &dbInsert($table, $primkey, %hash);
+#  Note: dbInsert does dbQuote.
+sub dbInsert {
+    my ($table, $primkey, %hash, $delay) = @_;
+    my (@keys, @vals);
+    my $p      = "";
+
+    if ($delay) {
+       &DEBUG("dbI: delay => $delay");
+       $p      = " DELAYED";
+    }
+
+    foreach (keys %hash) {
+       push(@keys, $_);
+       push(@vals, &dbQuote($hash{$_}));
+    }
+
+    &dbRaw("Insert($table)", "INSERT $p INTO $table (".join(',',@keys).
+               ") VALUES (".join(',',@vals).")"
+    );
+
+    return 1;
+}
+
+#####
+# Usage: &dbReplace($table, $key, %hash);
+#  Note: dbReplace does optional dbQuote.
+sub dbReplace {
+    my ($table, $key, %hash) = @_;
+    my (@keys, @vals);
+
+    foreach (keys %hash) {
+       if (s/^-//) {   # as is.
+           push(@keys, $_);
+           push(@vals, $hash{'-'.$_});
+       } else {
+           push(@keys, $_);
+           push(@vals, &dbQuote($hash{$_}));
+       }
+    }
+
+    if (0) {
+       &DEBUG("REPLACE INTO $table (".join(',',@keys).
+               ") VALUES (". join(',',@vals). ")" );
+    }
+
+    &dbRaw("Replace($table)", "REPLACE INTO $table (".join(',',@keys).
+               ") VALUES (". join(',',@vals). ")"
+    );
+
+    return 1;
+}
+
+#####
+# Usage: &dbSetRow($table, $vref, $delay);
+#  Note: dbSetRow does dbQuote.
+sub dbSetRow ($@$) {
+    my ($table, $vref, $delay) = @_;
+    my $p      = ($delay) ? " DELAYED " : "";
+
+    # see 'perldoc perlreftut'
+    my @values;
+    foreach (@{ $vref }) {
+       push(@values, &dbQuote($_) );
+    }
+
+    if (!scalar @values) {
+       &WARN("dbSetRow: values array == NULL.");
+       return;
+    }
+
+    return &dbRaw("SetRow", "INSERT $p INTO $table VALUES (".
+       join(",", @values) .")" );
+}
+
+#####
+# Usage: &dbDel($table, $primkey, $primval, [$key]);
+#  Note: dbDel does dbQuote
+sub dbDel {
+    my ($table, $primkey, $primval, $key) = @_;
+
+    &dbRaw("Del", "DELETE FROM $table WHERE $primkey=".
+               &dbQuote($primval)
+    );
+
+    return 1;
+}
+
+# Usage: &dbRaw($prefix,$rawquery);
+sub dbRaw {
+    my ($prefix,$query) = @_;
+    my $sth;
+
+    if (!($sth = $dbh->prepare($query))) {
+       &ERROR("Raw($prefix): $DBI::errstr");
+       return 0;
+    }
+
+#    &DEBUG("query => '$query'.");
+
+    &SQLDebug($query);
+    if (!$sth->execute) {
+       &ERROR("Raw($prefix): => '$query'");
+       # $DBI::errstr is printed as warning automatically.
+       $sth->finish;
+       return 0;
+    }
+
+    $sth->finish;
+
+    return 1;
+}
+
+# Usage: &dbRawReturn($rawquery);
+sub dbRawReturn {
+    my ($query) = @_;
+    my @retval;
+
+    my $sth = $dbh->prepare($query);
+    &SQLDebug($query);
+    &ERROR("RawReturn => '$query'.") unless $sth->execute;
+    while (my @row = $sth->fetchrow_array) {
+       push(@retval, $row[0]);
+    }
+    $sth->finish;
+
+    return @retval;
+}
+
+####################################################################
+##### Misc DBI stuff...
+#####
+
+#####
+# Usage: &countKeys($table, [$col]);
+sub countKeys {
+    my ($table, $col) = @_;
+    $col ||= "*";
+    &DEBUG("&countKeys($table, $col)");
+
+    return (&dbRawReturn("SELECT count($col) FROM $table"))[0];
+}
+
+# Usage: &sumKey($table, $col);
+sub sumKey {
+    my ($table, $col) = @_;
+
+    return (&dbRawReturn("SELECT sum($col) FROM $table"))[0];
+}
+
+#####
+# Usage: &randKey($table, $select);
+sub randKey {
+    my ($table, $select) = @_;
+    my $rand   = int(rand(&countKeys($table) - 1));
+    my $query  = "SELECT $select FROM $table LIMIT $rand,1";
+
+    my $sth    = $dbh->prepare($query);
+    &SQLDebug($query);
+    &WARN("randKey($query)") unless $sth->execute;
+    my @retval = $sth->fetchrow_array;
+    $sth->finish;
+
+    return @retval;
+}
+
+#####
+# Usage: &deleteTable($table);
+sub deleteTable {
+    &dbRaw("deleteTable($_[0])", "DELETE FROM $_[0]");
+}
+
+#####
+# Usage: &searchTable($table, $select, $key, $str);
+#  Note: searchTable does dbQuote.
+sub searchTable {
+    my($table, $select, $key, $str) = @_;
+    my $origStr = $str;
+    my @results;
+
+    # allow two types of wildcards.
+    if ($str =~ /^\^(.*)\$$/) {
+       &DEBUG("searchTable: should use dbGet(), heh.");
+       $str = $1;
+    } else {
+       $str .= "%"     if ($str =~ s/^\^//);
+       $str = "%".$str if ($str =~ s/\$$//);
+       $str = "%".$str."%" if ($str eq $origStr);      # el-cheapo fix.
+    }
+
+    $str =~ s/\_/\\_/g;
+    $str =~ s/\?/_/g;  # '.' should be supported, too.
+    $str =~ s/\*/%/g;  # for sqlite.
+    # end of string fix.
+
+    my $query = "SELECT $select FROM $table WHERE $key LIKE ". 
+               &dbQuote($str);
+    my $sth = $dbh->prepare($query);
+    &DEBUG("query => '$query'.");
+    &SQLDebug($query);
+    if (!$sth->execute) {
+       &WARN("Search($query)");
+       return;
+    }
+
+    while (my @row = $sth->fetchrow_array) {
+       push(@results, $row[0]);
+    }
+    $sth->finish;
+
+    return @results;
+}
+
+sub dbCreateTable {
+    my($table) = @_;
+    my(@path)  = ($bot_data_dir, ".","..","../..");
+    my $found  = 0;
+    my $data;
+
+    foreach (@path) {
+       my $file = "$_/setup/$table.sql";
+       &DEBUG("dbCT: file => $file");
+       next unless ( -f $file );
+
+       &DEBUG("dbCT: found!!!");
+
+       open(IN, $file);
+       while (<IN>) {
+           chop;
+           $data .= $_;
+       }
+
+       $found++;
+       last;
+    }
+
+    if (!$found) {
+       return 0;
+    } else {
+       &dbRaw("createTable($table)", $data);
+       return 1;
+    }
+}
+
+sub checkTables {
+    # retrieve a list of tables's from the server.
+    my %db;
+    foreach (&dbRawReturn("SELECT name FROM sqlite_master WHERE type='table'"))
+    {
+       $db{$_} = 1;
+    }
+
+    foreach ("factoids", "freshmeat", "rootwarn", "seen", "stats") {
+       next if (exists $db{$_});
+       &status("checkTables: creating $_...");
+
+       &dbCreateTable($_);
+    }
+}
+
+1;
index 0861982c778e89fe1a43388ea6d27d340947df56..ae2dac531699f771d1b09400cd0852303562b0a0 100644 (file)
@@ -105,12 +105,12 @@ sub loadDBModules {
        &status("Loading pgsql support.");
        require "$bot_src_dir/db_pgsql.pl";
        &showProc(" (pgsql)");
-    } elsif ($param{'DBType'} =~ /^dbm$/i) {
-       &status("Loading Berkeley DBM support.");
-       $f = "$bot_src_dir/db_dbm.pl";
-       require $f;
+    } elsif ($param{'DBType'} =~ /^sqlite$|^dbm$/i) {
+       &status("Loading " . $param{'DBType'} . " support.");
+       $f="$bot_src_dir/db_" . $param{'DBType'} . ".pl";
        $moduleAge{$f} = (stat $f)[9];
-       &showProc(" $bot_src_dir/db_dbm.pl");
+       require $f;
+       &showProc(" $bot_src_dir/db_" . $param{'DBType'} . ".pl");
     } else {
        &status("DB support DISABLED.");
        return;