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