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