]> git.donarmstrong.com Git - infobot.git/blob - src/db_mysql.pl
- modified db_mysql to allow eleet usage of dbSet
[infobot.git] / src / db_mysql.pl
1 #
2 # db_mysql.pl: MySQL database frontend.
3 #      Author: dms
4 #     Version: v0.2c (19991224)
5 #     Created: 19991203
6 #
7
8 package main;
9
10 if (&IsParam("useStrict")) { use strict; }
11
12 sub openDB {
13     my ($db, $user, $pass) = @_;
14     my $dsn = "DBI:mysql:$db:$param{'SQLHost'}";
15     $dbh    = DBI->connect($dsn, $user, $pass);
16
17     if ($dbh) {
18         &status("Opened MySQL connection to $param{'SQLHost'}");
19     } else {
20         &ERROR("cannot connect to $param{'SQLHost'}.");
21         &ERROR("since mysql is not available, shutting down bot!");
22         &shutdown();
23         &closePID();
24         exit 1;
25     }
26 }
27
28 sub closeDB {
29     return 0 unless ($dbh);
30
31     &status("Closed MySQL connection to $param{'SQLHost'}.");
32     $dbh->disconnect();
33     return 1;
34 }
35
36 #####
37 # Usage: &dbQuote($str);
38 sub dbQuote {
39     return $dbh->quote($_[0]);
40 }
41
42 #####
43 # Usage: &dbGet($table, $select, $where);
44 sub dbGet {
45     my ($table, $select, $where) = @_;
46     my $query    = "SELECT $select FROM $table";
47     $query      .= " WHERE $where" if ($where);
48
49     my $sth;
50     if (!($sth = $dbh->prepare($query))) {
51         &ERROR("Get: prepare: $DBI::errstr");
52         return;
53     }
54
55     &SQLDebug($query);
56     if (!$sth->execute) {
57         &ERROR("Get: execute: '$query'");
58         $sth->finish;
59         return 0;
60     }
61
62     my @retval = $sth->fetchrow_array;
63
64     $sth->finish;
65
66     if (scalar @retval > 1) {
67         return @retval;
68     } elsif (scalar @retval == 1) {
69         return $retval[0];
70     } else {
71         return;
72     }
73 }
74
75 #####
76 # Usage: &dbGetCol($table, $primkey, $key, [$type]);
77 sub dbGetCol {
78     my ($table, $primkey, $key, $type) = @_;
79     my $query = "SELECT $primkey,$key FROM $table WHERE $key IS NOT NULL";
80     my %retval;
81
82     my $sth = $dbh->prepare($query);
83     &SQLDebug($query);
84     if (!$sth->execute) {
85         &ERROR("GetCol: execute: '$query'");
86 #       &ERROR("GetCol => $DBI::errstr");
87         $sth->finish;
88         return;
89     }
90
91     if (defined $type and $type == 1) {
92         while (my @row = $sth->fetchrow_array) {
93             # reverse it to make it easier to count.
94             $retval{$row[1]}{$row[0]} = 1;
95         }
96     } else {
97         while (my @row = $sth->fetchrow_array) {
98             $retval{$row[0]} = $row[1];
99         }
100     }
101
102     $sth->finish;
103
104     return %retval;
105 }
106
107 ####
108 # Usage: &dbGetColInfo($table);
109 sub dbGetColInfo {
110     my ($table) = @_;
111
112     my $query = "SHOW COLUMNS from $table";
113     my %retval;
114
115     my $sth = $dbh->prepare($query);
116     &SQLDebug($query);
117     if (!$sth->execute) {
118         &ERROR("GRI => '$query'");
119         &ERROR("GRI => $DBI::errstr");
120         $sth->finish;
121         return;
122     }
123
124     my @cols;
125     while (my @row = $sth->fetchrow_array) {
126         push(@cols, $row[0]);
127     }
128     $sth->finish;
129
130     return @cols;
131 }
132
133 #####
134 # Usage: &dbSet($table, $primhash_ref, $hash_ref);
135 sub dbSet {
136     my ($table, $phref, $href) = @_;
137     my $where = join(' AND ', map {
138                 $_."=".&dbQuote($phref->{$_})
139         } keys %{$phref}
140     );
141
142     my $result = &dbGet($table, join(',', keys %{$phref}), $where);
143
144     my(@keys,@vals);
145     foreach (keys %{$href}) {
146         push(@keys, $_);
147         push(@vals, &dbQuote($href->{$_}) );
148     }
149
150     if (!@keys or !@vals) {
151         &WARN("dbset: keys or vals is NULL.");
152         return;
153     }
154
155     my $query;
156     if (defined $result) {
157         my @keyval;
158         for(my$i=0; $i<scalar @keys; $i++) {
159             push(@keyval, $keys[$i]."=".$vals[$i] );
160         }
161
162         $query = "UPDATE $table SET ".
163                 join(' AND ', @keyval).
164                 " WHERE ".$where;
165     } else {
166         foreach (keys %{$phref}) {
167             push(@keys, $_);
168             push(@vals, &dbQuote($phref->{$_}) );
169         }
170
171         $query = sprintf("INSERT INTO $table (%s) VALUES (%s)",
172                 join(',',@keys), join(',',@vals) );
173     }
174
175     &dbRaw("Set", $query);
176
177     return 1;
178 }
179
180 #####
181 # Usage: &dbUpdate($table, $primkey, $primval, %hash);
182 sub dbUpdate {
183     my ($table, $primkey, $primval, %hash) = @_;
184     my (@array);
185
186     foreach (keys %hash) {
187         push(@array, "$_=".&dbQuote($hash{$_}) );
188     }
189
190     &dbRaw("Update", "UPDATE $table SET ".join(', ', @array).
191                 " WHERE $primkey=".&dbQuote($primval)
192     );
193
194     return 1;
195 }
196
197 #####
198 # Usage: &dbInsert($table, $primkey, %hash);
199 sub dbInsert {
200     my ($table, $primkey, %hash, $delay) = @_;
201     my (@keys, @vals);
202     my $p       = "";
203
204     if ($delay) {
205         &DEBUG("dbI: delay => $delay");
206         $p      = " DELAYED";
207     }
208
209     foreach (keys %hash) {
210         push(@keys, $_);
211         push(@vals, &dbQuote($hash{$_}));
212     }
213
214     &dbRaw("Insert($table)", "INSERT $p INTO $table (".join(',',@keys).
215                 ") VALUES (".join(',',@vals).")"
216     );
217
218     return 1;
219 }
220
221 #####
222 # Usage: &dbReplace($table, %hash);
223 sub dbReplace {
224     my ($table, %hash) = @_;
225     my (@keys, @vals);
226
227     foreach (keys %hash) {
228         if (s/^-//) {   # as is.
229             push(@keys, $_);
230             push(@vals, $hash{'-'.$_});
231         } else {
232             push(@keys, $_);
233             push(@vals, &dbQuote($hash{$_}));
234         }
235     }
236
237     &dbRaw("Replace($table)", "REPLACE INTO $table (".join(',',@keys).
238                 ") VALUES (". join(',',@vals). ")"
239     );
240
241     return 1;
242 }
243
244 #####
245 # Usage: &dbSetRow($table, @values);
246 sub dbSetRow ($@$) {
247     my ($table, @values, $delay) = @_;
248     my $p       = ($delay) ? " DELAYED " : "";
249
250     foreach (@values) {
251         $_ = &dbQuote($_);
252     }
253
254     return &dbRaw("SetRow", "INSERT $p INTO $table VALUES (".
255         join(",", @values) .")" );
256 }
257
258 #####
259 # Usage: &dbDel($table, $primkey, $primval, [$key]);
260 sub dbDel {
261     my ($table, $primkey, $primval, $key) = @_;
262
263     &dbRaw("Del", "DELETE FROM $table WHERE $primkey=".
264                 &dbQuote($primval)
265     );
266
267     return 1;
268 }
269
270 # Usage: &dbRaw($prefix,$rawquery);
271 sub dbRaw {
272     my ($prefix,$query) = @_;
273     my $sth;
274
275     if (!($sth = $dbh->prepare($query))) {
276         &ERROR("Raw($prefix): $DBI::errstr");
277         return 0;
278     }
279
280 #    &DEBUG("query => '$query'.");
281
282     &SQLDebug($query);
283     if (!$sth->execute) {
284         &ERROR("Raw($prefix): => '$query'");
285         # $DBI::errstr is printed as warning automatically.
286         $sth->finish;
287         return 0;
288     }
289
290     $sth->finish;
291
292     return 1;
293 }
294
295 # Usage: &dbRawReturn($rawquery);
296 sub dbRawReturn {
297     my ($query) = @_;
298     my @retval;
299
300     my $sth = $dbh->prepare($query);
301     &SQLDebug($query);
302     &ERROR("RawReturn => '$query'.") unless $sth->execute;
303     while (my @row = $sth->fetchrow_array) {
304         push(@retval, $row[0]);
305     }
306     $sth->finish;
307
308     return @retval;
309 }
310
311 ####################################################################
312 ##### Misc DBI stuff...
313 #####
314
315 #####
316 # Usage: &countKeys($table, [$col]);
317 sub countKeys {
318     my ($table, $col) = @_;
319     $col ||= "*";
320
321     return (&dbRawReturn("SELECT count($col) FROM $table"))[0];
322 }
323
324 # Usage: &sumKey($table, $col);
325 sub sumKey {
326     my ($table, $col) = @_;
327
328     return (&dbRawReturn("SELECT sum($col) FROM $table"))[0];
329 }
330
331 ##### NOT USED.
332 # Usage: &getKeys($table,$primkey);
333 sub getKeys {
334     my ($table,$primkey) = @_;
335     my @retval;
336
337     my $query   = "SELECT $primkey FROM $table";
338     my $sth     = $dbh->prepare($query);
339
340     &SQLDebug($query);
341     &WARN("ERROR: getKeys($query)") unless $sth->execute;
342
343     while (my @row = $sth->fetchrow_array) {
344         push(@retval, $row[0]);
345     }
346     $sth->finish;
347
348     return @retval;
349 }
350
351 #####
352 # Usage: &randKey($table, $select);
353 sub randKey {
354     my ($table, $select) = @_;
355     my $rand    = int(rand(&countKeys($table) - 1));
356     my $query   = "SELECT $select FROM $table LIMIT $rand,1";
357
358     my $sth     = $dbh->prepare($query);
359     &SQLDebug($query);
360     &WARN("randKey($query)") unless $sth->execute;
361     my @retval  = $sth->fetchrow_array;
362     $sth->finish;
363
364     return @retval;
365 }
366
367 #####
368 # Usage: &deleteTable($table);
369 sub deleteTable {
370     &dbRaw("deleteTable($_[0])", "DELETE FROM $_[0]");
371 }
372
373 # Usage: &searchTable($table, $select, $key, $str);
374 sub searchTable {
375     my($table, $select, $key, $str) = @_;
376     my $origStr = $str;
377     my @results;
378
379     # allow two types of wildcards.
380     if ($str =~ /^\^(.*)\$$/) {
381         &DEBUG("searchTable: should use dbGet(), heh.");
382         $str = $1;
383     } else {
384         $str .= "%"     if ($str =~ s/^\^//);
385         $str = "%".$str if ($str =~ s/\$$//);
386         $str = "%".$str."%" if ($str eq $origStr);      # el-cheapo fix.
387     }
388
389     $str =~ s/\_/\\_/g;
390     $str =~ s/\?/\_/g;  # '.' should be supported, too.
391     # end of string fix.
392
393     my $query = "SELECT $select FROM $table WHERE $key LIKE ". 
394                 &dbQuote($str);
395     my $sth = $dbh->prepare($query);
396     &SQLDebug($query);
397     &WARN("Search($query)") unless $sth->execute;
398
399     while (my @row = $sth->fetchrow_array) {
400         push(@results, $row[0]);
401     }
402     $sth->finish;
403
404     return @results;
405 }
406
407 ####################################################################
408 ##### Factoid related stuff...
409 #####
410
411 #####
412 # Usage: &getFactInfo($faqtoid, type);
413 sub getFactInfo {
414     return &dbGet("factoids", $_[1], "factoid_key='$_[0]'");
415 }
416
417 #####
418 # Usage: &getFactoid($faqtoid);
419 sub getFactoid {
420     return &getFactInfo($_[0], "factoid_value");
421 }
422
423 #####
424 # Usage: &delFactoid($faqtoid);
425 sub delFactoid {
426     my ($faqtoid) = @_;
427
428     &dbDel("factoids", "factoid_key",$faqtoid);
429     &status("DELETED '$faqtoid'");
430
431     return 1;
432 }
433
434 sub SQLDebug {
435     return unless (&IsParam("SQLDebug"));
436
437     return if (!fileno SQLDEBUG);
438
439     print SQLDEBUG $_[0]."\n";
440 }
441
442 sub dbCreateTable {
443     my($table)  = @_;
444     my(@path)   = (".","..","../..");
445     my $found   = 0;
446     my $data;
447
448     foreach (@path) {
449         my $file = "$_/setup/$table.sql";
450         &DEBUG("dbCT: file => $file");
451         next unless ( -f $file );
452
453         &DEBUG("found!!!");
454
455         open(IN, $file);
456         while (<IN>) {
457             chop;
458             $data .= $_;
459         }
460
461         $found++;
462         last;
463     }
464
465     if (!$found) {
466         return 0;
467     } else {
468         &dbRaw("create($table)", $data);
469         return 1;
470     }
471 }
472
473 sub checkTables {
474     # retrieve a list of db's from the server.
475     my %db;
476     foreach ($dbh->func('_ListTables')) {
477         $db{$_} = 1;
478     }
479
480     # create database.
481     if (!scalar keys %db) {
482         &status("Creating database $param{'DBName'}...");
483         $query = "CREATE DATABASE $param{'DBName'}";
484         &dbRaw("create(db $param{'DBName'})", $query);
485     }
486
487     foreach ("factoids", "freshmeat", "rootwarn", "seen", "stats",
488     ) {
489         next if (exists $db{$_});
490         &status("  creating new table $_...");
491
492         &dbCreateTable($_);
493     }
494 }
495
496 1;