]> git.donarmstrong.com Git - infobot.git/blob - src/db_mysql.pl
d5f7b43f9960b878dcf3e807531a211160e32cb4
[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: $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, "$primkey='$primval'");
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, %hash);
197 sub dbReplace {
198     my ($table, %hash) = @_;
199     my (@keys, @vals);
200
201     foreach (keys %hash) {
202         if (s/^-//) {   # as is.
203             push(@keys, $_);
204             push(@vals, $hash{'-'.$_});
205         } else {
206             push(@keys, $_);
207             push(@vals, &dbQuote($hash{$_}));
208         }
209     }
210
211     &dbRaw("Replace($table)", "REPLACE INTO $table (".join(',',@keys).
212                 ") VALUES (". join(',',@vals). ")"
213     );
214
215     return 1;
216 }
217
218 #####
219 # Usage: &dbSetRow($table, @values);
220 sub dbSetRow ($@$) {
221     my ($table, @values, $delay) = @_;
222     my $p       = ($delay) ? " DELAYED " : "";
223
224     foreach (@values) {
225         $_ = &dbQuote($_);
226     }
227
228     return &dbRaw("SetRow", "INSERT $p INTO $table VALUES (".
229         join(",", @values) .")" );
230 }
231
232 #####
233 # Usage: &dbDel($table, $primkey, $primval, [$key]);
234 sub dbDel {
235     my ($table, $primkey, $primval, $key) = @_;
236
237     &dbRaw("Del", "DELETE FROM $table WHERE $primkey=".
238                 &dbQuote($primval)
239     );
240
241     return 1;
242 }
243
244 # Usage: &dbRaw($prefix,$rawquery);
245 sub dbRaw {
246     my ($prefix,$query) = @_;
247     my $sth;
248
249     if (!($sth = $dbh->prepare($query))) {
250         &ERROR("Raw($prefix): $DBI::errstr");
251         return 0;
252     }
253
254 #    &DEBUG("query => '$query'.");
255
256     &SQLDebug($query);
257     if (!$sth->execute) {
258         &ERROR("Raw($prefix): => '$query'");
259         # $DBI::errstr is printed as warning automatically.
260         $sth->finish;
261         return 0;
262     }
263
264     $sth->finish;
265
266     return 1;
267 }
268
269 # Usage: &dbRawReturn($rawquery);
270 sub dbRawReturn {
271     my ($query) = @_;
272     my @retval;
273
274     my $sth = $dbh->prepare($query);
275     &SQLDebug($query);
276     &ERROR("RawReturn => '$query'.") unless $sth->execute;
277     while (my @row = $sth->fetchrow_array) {
278         push(@retval, $row[0]);
279     }
280     $sth->finish;
281
282     return @retval;
283 }
284
285 ####################################################################
286 ##### Misc DBI stuff...
287 #####
288
289 #####
290 # Usage: &countKeys($table, [$col]);
291 sub countKeys {
292     my ($table, $col) = @_;
293     $col ||= "*";
294
295     return (&dbRawReturn("SELECT count($col) FROM $table"))[0];
296 }
297
298 # Usage: &sumKey($table, $col);
299 sub sumKey {
300     my ($table, $col) = @_;
301
302     return (&dbRawReturn("SELECT sum($col) FROM $table"))[0];
303 }
304
305 ##### NOT USED.
306 # Usage: &getKeys($table,$primkey);
307 sub getKeys {
308     my ($table,$primkey) = @_;
309     my @retval;
310
311     my $query   = "SELECT $primkey FROM $table";
312     my $sth     = $dbh->prepare($query);
313
314     &SQLDebug($query);
315     &WARN("ERROR: getKeys($query)") unless $sth->execute;
316
317     while (my @row = $sth->fetchrow_array) {
318         push(@retval, $row[0]);
319     }
320     $sth->finish;
321
322     return @retval;
323 }
324
325 #####
326 # Usage: &randKey($table, $select);
327 sub randKey {
328     my ($table, $select) = @_;
329     my $rand    = int(rand(&countKeys($table) - 1));
330     my $query   = "SELECT $select FROM $table LIMIT $rand,1";
331
332     my $sth     = $dbh->prepare($query);
333     &SQLDebug($query);
334     &WARN("randKey($query)") unless $sth->execute;
335     my @retval  = $sth->fetchrow_array;
336     $sth->finish;
337
338     return @retval;
339 }
340
341 #####
342 # Usage: &deleteTable($table);
343 sub deleteTable {
344     &dbRaw("deleteTable($_[0])", "DELETE FROM $_[0]");
345 }
346
347 # Usage: &searchTable($table, $select, $key, $str);
348 sub searchTable {
349     my($table, $select, $key, $str) = @_;
350     my $origStr = $str;
351     my @results;
352
353     # allow two types of wildcards.
354     if ($str =~ /^\^(.*)\$$/) {
355         &DEBUG("searchTable: should use dbGet(), heh.");
356         $str = $1;
357     } else {
358         $str .= "%"     if ($str =~ s/^\^//);
359         $str = "%".$str if ($str =~ s/\$$//);
360         $str = "%".$str."%" if ($str eq $origStr);      # el-cheapo fix.
361     }
362
363     $str =~ s/\_/\\_/g;
364     $str =~ s/\?/\_/g;  # '.' should be supported, too.
365     # end of string fix.
366
367     my $query = "SELECT $select FROM $table WHERE $key LIKE ". 
368                 &dbQuote($str);
369     my $sth = $dbh->prepare($query);
370     &SQLDebug($query);
371     &WARN("Search($query)") unless $sth->execute;
372
373     while (my @row = $sth->fetchrow_array) {
374         push(@results, $row[0]);
375     }
376     $sth->finish;
377
378     return @results;
379 }
380
381 ####################################################################
382 ##### Factoid related stuff...
383 #####
384
385 #####
386 # Usage: &getFactInfo($faqtoid, type);
387 sub getFactInfo {
388     return &dbGet("factoids", $_[1], "factoid_key='$_[0]'");
389 }
390
391 #####
392 # Usage: &getFactoid($faqtoid);
393 sub getFactoid {
394     return &getFactInfo($_[0], "factoid_value");
395 }
396
397 #####
398 # Usage: &delFactoid($faqtoid);
399 sub delFactoid {
400     my ($faqtoid) = @_;
401
402     &dbDel("factoids", "factoid_key",$faqtoid);
403     &status("DELETED '$faqtoid'");
404
405     return 1;
406 }
407
408 sub SQLDebug {
409     return unless (&IsParam("SQLDebug"));
410
411     return if (!fileno SQLDEBUG);
412
413     print SQLDEBUG $_[0]."\n";
414 }
415
416 sub dbCreateTable {
417     my($table)  = @_;
418     my(@path)   = (".","..","../..");
419     my $found   = 0;
420     my $data;
421
422     foreach (@path) {
423         my $file = "$_/setup/$table.sql";
424         &DEBUG("dbCT: file => $file");
425         next unless ( -f $file );
426
427         &DEBUG("found!!!");
428
429         open(IN, $file);
430         while (<IN>) {
431             chop;
432             $data .= $_;
433         }
434
435         $found++;
436         last;
437     }
438
439     if (!$found) {
440         return 0;
441     } else {
442         &dbRaw("create($table)", $data);
443         return 1;
444     }
445 }
446
447 sub checkTables {
448     # retrieve a list of db's from the server.
449     my %db;
450     foreach ($dbh->func('_ListTables')) {
451         $db{$_} = 1;
452     }
453
454     # create database.
455     if (!scalar keys %db) {
456         &status("Creating database $param{'DBName'}...");
457         $query = "CREATE DATABASE $param{'DBName'}";
458         &dbRaw("create(db $param{'DBName'})", $query);
459     }
460
461     foreach ("factoids", "freshmeat", "rootwarn", "seen", "stats",
462     ) {
463         next if (exists $db{$_});
464         &status("  creating new table $_...");
465
466         &dbCreateTable($_);
467     }
468 }
469
470 1;