Annotation of botnow/SQLite.pm, Revision 1.1
1.1 ! bountyht 1: #!/usr/bin/perl
! 2:
! 3: package SQLite;
! 4:
! 5: use strict;
! 6: use warnings;
! 7: use OpenBSD::Pledge;
! 8: use OpenBSD::Unveil;
! 9: use Data::Dumper;
! 10: use DBI;
! 11: use DBD::SQLite;
! 12:
! 13: use constant {
! 14: NONE => 0,
! 15: ERRORS => 1,
! 16: WARNINGS => 2,
! 17: ALL => 3,
! 18: };
! 19: my %conf = %main::conf;
! 20: my $staff = $conf{staff};
! 21: my $dbh;
! 22: my $verbose = $conf{verbose};
! 23: my $dbpath = "/var/www/botnow/botnow.db";
! 24: my $database = "/var/www/botnow/"; # database path
! 25: main::cbind("msg", "-", "get", \&mget);
! 26: main::cbind("msg", "-", "set", \&mset);
! 27: main::cbind("msg", "-", "connectdb", \&mconnectdb);
! 28: main::cbind("msg", "-", "insert", \&minsert);
! 29: main::cbind("msg", "-", "update", \&mupdate);
! 30: main::cbind("msg", "-", "delete", \&mdelete);
! 31: main::cbind("msg", "-", "select", \&mselect);
! 32:
! 33: sub init {
! 34: unveil("$dbpath", "rwc") or die "Unable to unveil $!";
! 35: unveil("$dbpath-journal", "rwc") or die "Unable to unveil $!";
! 36: unveil("$database", "rwxc") or die "Unable to unveil $!";
! 37: }
! 38:
! 39: # !connectdb
! 40: sub mconnectdb {
! 41: my ($bot, $nick, $host, $hand, $text) = @_;
! 42: if (! (main::isstaff($bot, $nick))) { return; }
! 43: if (connectdb()) {
! 44: main::putserv($bot, "PRIVMSG $nick :connectdb succeeded");
! 45: } else {
! 46: main::putserv($bot, "PRIVMSG $nick :ERROR: connectdb failed");
! 47: }
! 48: }
! 49:
! 50: # !insert <table> <keys> <vals>
! 51: # Insert comma-separated keys and vals into table
! 52: sub minsert {
! 53: my ($bot, $nick, $host, $hand, $text) = @_;
! 54: if (! (main::isstaff($bot, $nick))) { return; }
! 55: if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_~@!,\.[:alnum:]]+)\s+([[:ascii:]]+)/) {
! 56: my ($table, $keys, $vals) = ($1, $2, $3);
! 57: # strings in the values must be quoted
! 58: if ($vals =~ s{,}{","}g) { $vals = '"'.$vals.'"'; }
! 59: if (insertrow($table, $keys, $vals)) {
! 60: main::putserv($bot, "PRIVMSG $nick :$table ($keys) => ($vals)");
! 61: } else {
! 62: main::putserv($bot, "PRIVMSG $nick :$table insert failed");
! 63: }
! 64: } else {
! 65: main::putserv($bot, "PRIVMSG $nick :invalid insert");
! 66: }
! 67: }
! 68:
! 69: # Set key = val where idkey = idval in table
! 70: # !update <table> <idkey> <idval> <key> <val>
! 71: sub mupdate {
! 72: my ($bot, $nick, $host, $hand, $text) = @_;
! 73: if (! (main::isstaff($bot, $nick))) { return; }
! 74: if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_~@!,\.[:alnum:]]+)\s+(\S+)\s+([-_[:alnum:]]+)\s+(\S+)/) {
! 75: my ($table, $idkey, $idval, $key, $val) = ($1, $2, $3, $4, $5);
! 76: if (updaterow($table, $idkey, $idval, $key, $val)) {
! 77: main::putserv($bot, "PRIVMSG $nick :$table $key => $val where $idkey = $idval");
! 78: } else {
! 79: main::putserv($bot, "PRIVMSG $nick :update failed");
! 80: }
! 81: } else {
! 82: main::putserv($bot, "PRIVMSG $nick :invalid update");
! 83: }
! 84: }
! 85:
! 86: # Delete rows where key = val in table
! 87: # !delete <table> <key> <val>
! 88: sub mdelete {
! 89: my ($bot, $nick, $host, $hand, $text) = @_;
! 90: if (! (main::isstaff($bot, $nick))) { return; }
! 91: if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_[:alnum:]]+)\s+(\S+)/) {
! 92: my ($table, $key, $val) = ($1, $2, $3);
! 93: if (deleterows($table, $key, $val)) {
! 94: main::putserv($bot, "PRIVMSG $nick :$table $key = $val deleted");
! 95: } else {
! 96: main::putserv($bot, "PRIVMSG $nick :delete failed");
! 97: }
! 98: } else {
! 99: main::putserv($bot, "PRIVMSG $nick :invalid delete");
! 100: }
! 101: }
! 102:
! 103: # Output rows where key = val in table
! 104: # !select <table> <key> <val>
! 105: sub mselect {
! 106: my ($bot, $nick, $host, $hand, $text) = @_;
! 107: if (! (main::isstaff($bot, $nick))) { return; }
! 108: if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_[:alnum:]]+)\s+(\S+)/) {
! 109: my ($table, $key, $val) = ($1, $2, $3);
! 110: my @rows = selectrows($table, $key, $val);
! 111: if (@rows) {
! 112: foreach my $row (@rows) {
! 113: my @pairs;
! 114: foreach $key (keys %$row) {
! 115: my $val = $row->{$key} || "";
! 116: push(@pairs, "$key => $val");
! 117: }
! 118: main::putserv($bot, "PRIVMSG $nick :$table ".join(',', @pairs));
! 119: }
! 120: } else {
! 121: main::putserv($bot, "PRIVMSG $nick :no results");
! 122: }
! 123: } else {
! 124: main::putserv($bot, "PRIVMSG $nick :select invalid");
! 125: }
! 126: }
! 127:
! 128: # Get value of key where idkey = idval in table
! 129: # !get <table> <idkey> <idval> <key>
! 130: sub mget {
! 131: my ($bot, $nick, $host, $hand, $text) = @_;
! 132: if (! (main::isstaff($bot, $nick))) { return; }
! 133: if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_~@!,\.[:alnum:]]+)\s+(\S+)\s+([-_[:alnum:]]+)/) {
! 134: my ($table, $idkey, $idval, $key) = ($1, $2, $3, $4);
! 135: my $val = get($table, $idkey, $idval, $key);
! 136: if (defined($val)) {
! 137: main::putserv($bot, "PRIVMSG $nick :$table $key => $val where $idkey = $idval");
! 138: } else {
! 139: main::putserv($bot, "PRIVMSG $nick :undefined");
! 140: }
! 141: } else {
! 142: main::putserv($bot, "PRIVMSG $nick :invalid get");
! 143: }
! 144: }
! 145: # !set <table> <idkey> <idval> <key> <val>
! 146: sub mset {
! 147: my ($bot, $nick, $host, $hand, $text) = @_;
! 148: if (! (main::isstaff($bot, $nick))) { return; }
! 149: if ($text =~ /^([-_~@!,\.[:alnum:]]+)\s+([-_~@!,\.[:alnum:]]+)\s+(\S+)\s+([-_[:alnum:]]+)\s+(\S+)/) {
! 150: my ($table, $idkey, $idval, $key, $val) = ($1, $2, $3, $4, $5);
! 151: if (set($table, $idkey, $idval, $key, $val)) {
! 152: main::putserv($bot, "PRIVMSG $nick :$table $key => $val where $idkey = $idval");
! 153: } else {
! 154: main::putserv($bot, "PRIVMSG $nick :failed set");
! 155: }
! 156: } else {
! 157: main::putserv($bot, "PRIVMSG $nick :invalid set");
! 158: }
! 159: }
! 160:
! 161: # Connect to database, creating table if necessary
! 162: # Returns true on success, false on failure
! 163: sub connectdb {
! 164: my $dsn = "dbi:SQLite:dbname=$dbpath";
! 165: my $user = "";
! 166: my $password = "";
! 167: $dbh = DBI->connect($dsn, $user, $password, {
! 168: PrintError => 1,
! 169: RaiseError => 1,
! 170: AutoCommit => 1,
! 171: FetchHashKeyName => 'NAME_lc',
! 172: }) or die "Couldn't connect to database: " . $DBI::errstr;
! 173: if (!(-s "$dbpath")) {
! 174: my $sql = main::readstr('table.sql');
! 175: my @sql = split /;/m, $sql;
! 176: foreach my $s (@sql) {
! 177: $dbh->do($s);
! 178: }
! 179: }
! 180: main::debug(ALL, "connected to $dbpath");
! 181: return defined($dbh);
! 182: }
! 183:
! 184: # Inserts comma-separated keys and vals into table
! 185: # Returns number of rows successfully inserted
! 186: sub insertrow {
! 187: my ($table, $keys, $vals) = @_;
! 188: if (!defined($dbh)) { connectdb(); }
! 189: my $rows = $dbh->do("INSERT INTO $table ($keys) values ($vals)");
! 190: if ($rows) {
! 191: main::debug(ALL, "INSERT INTO $table ($keys) values ($vals)");
! 192: } else {
! 193: main::debug(ERRORS, "ERRORS: Failed INSERT INTO $table ($keys) values ($vals)");
! 194: }
! 195: return $rows;
! 196: }
! 197:
! 198: # Update key, value pair for record where idkey equals idval in table
! 199: # Returns number of rows successfully updated
! 200: sub updaterow {
! 201: my ($table, $idkey, $idval, $key, $val) = @_;
! 202: if (!defined($dbh)) { connectdb(); }
! 203: my $rows = $dbh->do("UPDATE $table SET $key = ? where $idkey = ?", undef, $val, $idval);
! 204: if ($rows) {
! 205: main::debug(ALL, "UPDATE $table SET $key = $val where $idkey = $idval");
! 206: } else {
! 207: main::debug(ERRORS, "ERRORS: Failed UPDATE $table SET $key = $val where $idkey = $idval");
! 208: }
! 209: return $rows;
! 210: }
! 211:
! 212: # Delete records from $table where $key = $val
! 213: # Returns number of rows deleted
! 214: sub deleterows {
! 215: my ($table, $key, $val) = @_;
! 216: if (!defined($dbh)) { connectdb(); }
! 217: my $rows = $dbh->do("DELETE FROM $table WHERE $key = ?", undef, $val);
! 218: if ($rows) {
! 219: main::debug(ALL, "DELETE FROM $table WHERE $key = $val");
! 220: } else {
! 221: main::debug(ERRORS, "ERRORS: Failed DELETE FROM $table WHERE $key = $val");
! 222: }
! 223: return $rows;
! 224: }
! 225:
! 226: # Returns all records in the database
! 227: sub selectall {
! 228: my ($table) = @_;
! 229: if (!defined($dbh)) { connectdb(); }
! 230: my $sth = $dbh->prepare("SELECT * FROM $table");
! 231: $sth->execute();
! 232: my @results;
! 233: while (my $row = $sth->fetchrow_hashref) {
! 234: push(@results, $row);
! 235: }
! 236: return @results;
! 237: }
! 238:
! 239: # Returns all records from table where key equals value
! 240: sub selectrows {
! 241: my ($table, $key, $val) = @_;
! 242: if (!defined($dbh)) { connectdb(); }
! 243: my $sth = $dbh->prepare("SELECT * FROM $table WHERE $key = ?");
! 244: $sth->execute($val);
! 245: my @results;
! 246: while (my $row = $sth->fetchrow_hashref) {
! 247: push(@results, $row);
! 248: }
! 249: return @results;
! 250: }
! 251:
! 252: # Returns list of tables
! 253: sub tables {
! 254: # if (!defined($dbh)) { connectdb(); }
! 255: # my $sth = $dbh->prepare(".tables");
! 256: # $sth->execute($val);
! 257: # my @results;
! 258: # while (my $row = $sth->fetchrow_hashref) {
! 259: # push(@results, $row);
! 260: # }
! 261: # return @results;
! 262: return qw(bnc shell www irc smtp);
! 263: }
! 264:
! 265: # Returns value of key in record in table where idkey = idval
! 266: sub get {
! 267: my ($table, $idkey, $idval, $key) = @_;
! 268: if (!defined($dbh)) { connectdb(); }
! 269: my $sth = $dbh->prepare("SELECT * FROM $table WHERE $idkey = ?");
! 270: $sth->execute($idval);
! 271: if (my $row = $sth->fetchrow_hashref) {
! 272: my $val = $row->{$key};
! 273: if (!defined($val)) { $val = "undefined"; }
! 274: main::debug(ALL, "get: $table $key => $val where $idkey = $idval");
! 275: return $row->{$key};
! 276: } else {
! 277: main::debug(ERRORS, "ERRORS: $table $key undefined where $idkey = $idval");
! 278: return;
! 279: }
! 280: }
! 281:
! 282: # Sets value of key in the record in table where idkey = idval
! 283: # Returns true on success; false on failure
! 284: sub set {
! 285: my ($table, $idkey, $idval, $key, $val) = @_;
! 286: if (defined(get($table, $idkey, $idval, $idkey))) {
! 287: main::debug(ALL, "set: update");
! 288: return updaterow($table, $idkey, $idval, $key, $val) > 0;
! 289: } else {
! 290: main::debug(ALL, "set: insert");
! 291: return insertrow($table, "$idkey,$key", "\"$idval\",\"$val\"") > 0;
! 292: }
! 293: }
! 294:
! 295: # given a key, val pair in table, return the id that falls within expires seconds
! 296: sub id {
! 297: my ($table, $key, $val, $expires) = @_;
! 298: my @rows = selectrows($table, $key, $val);
! 299: if (scalar(@rows) == 0) {
! 300: print "table => $table, key => $key, val => $val\n\n";
! 301: }
! 302: my $maxrow;
! 303: foreach my $row (@rows) {
! 304: if (!defined($maxrow)) { $maxrow = $row; }
! 305: if ($row->{localtime} > $maxrow->{localtime}) {
! 306: $maxrow = $row;
! 307: }
! 308: }
! 309: if (abs(time() - $maxrow->{localtime}) <= $expires) {
! 310: main::debug(ALL, "id: $maxrow->{id} where $key = $val at $expires");
! 311: return $maxrow->{id};
! 312: } else {
! 313: main::debug(ERRORS, "no id found");
! 314: return;
! 315: }
! 316: }
! 317:
! 318: 1; # MUST BE LAST STATEMENT IN FILE
CVSweb