bugfix
[koha.git] / updater / updatedatabase
1 #!/usr/bin/perl
2
3 # $Id$
4
5 # Database Updater
6 # This script checks for required updates to the database.  
7
8 # Part of the Koha Library Software www.koha.org
9 # Licensed under the GPL.
10
11 # Bugs/ToDo: 
12 # - Would also be a good idea to offer to do a backup at this time...
13
14 # NOTE:  If you do something more than once in here, make it table driven.
15
16 use strict;
17
18 # CPAN modules
19 use DBI;
20
21 # Koha modules
22 use C4::Context;
23         # FIXME - /etc/koha.conf might not exist, so shouldn't use
24         # C4::Context.
25
26 # FIXME - The user might be installing a new database, so can't rely
27 # on /etc/koha.conf anyway.
28
29 my $debug=0;
30
31 my (
32         $sth, $sti,
33         $query,
34         %existingtables,        # tables already in database
35         %types,
36         $table,
37         $column,
38         $type, $null, $key, $default, $extra,
39         $prefitem,              # preference item in systempreferences table
40 );
41
42 #-------------------
43 # Defines
44
45 # Tables to add if they don't exist
46 my %requiretables=(
47     shelfcontents=>"( shelfnumber int not null, 
48         itemnumber int not null, 
49         flags int)",
50     bookshelf=>"( shelfnumber int auto_increment primary key, 
51         shelfname char(255))",
52     z3950queue=>"( id int auto_increment primary key, 
53         term text, 
54         type char(10), 
55         startdate int, 
56         enddate int,
57         done smallint, 
58         results longblob, 
59         numrecords int, 
60         servers text, 
61         identifier char(30))",
62     z3950results=>"( id int auto_increment primary key, 
63         queryid int, 
64         server char(255), 
65         startdate int, 
66         enddate int, 
67         results longblob, 
68         numrecords int, 
69         numdownloaded int, 
70         highestseen int, 
71         active smallint)",
72     branchrelations=>"( branchcode varchar(4), 
73         categorycode varchar(4))",
74     websites=>"( websitenumber int(11) NOT NULL auto_increment,
75         biblionumber int(11) NOT NULL default '0',
76         title text,
77         description text,
78         url varchar(255),
79         PRIMARY KEY (websitenumber) )",
80     marcrecorddone=>"( isbn char(40),
81                       issn char(40),
82                       lccn char(40),
83                       controlnumber char(40))",
84     uploadedmarc=>"( id int(11) NOT NULL auto_increment PRIMARY KEY,
85                     marc longblob,
86                     hidden smallint(6) default NULL,
87                     name varchar(255) default NULL)",
88     ethnicity=>"( code varchar(10) NOT NULL default '',
89                 name varchar(255) default NULL,
90                 PRIMARY KEY  (code)   )",
91     sessions=>"( sessionID varchar(255) NOT NULL default '',
92                 userid varchar(255) default NULL,
93                 ip varchar(16) default NULL,
94                 lasttime int,
95                 PRIMARY KEY (sessionID)   )",
96     sessionqueries=>"( sessionID varchar(255) NOT NULL default '',
97                        userid char(100) NOT NULL default '',
98                        ip char(18) NOT NULL default '',
99                        url text NOT NULL default ''  )",
100     bibliothesaurus=> "( code BIGINT not null AUTO_INCREMENT, 
101                          freelib CHAR (255) not null , 
102                          stdlib CHAR (255) not null , 
103                          type CHAR (80) not null , 
104                          PRIMARY KEY (code), 
105                          INDEX (freelib),index(stdlib),index(type) )",
106     marc_biblio => "(
107                          bibid bigint(20) unsigned NOT NULL auto_increment,
108                          biblionumber int(11) NOT NULL default '0',
109                          datecreated date NOT NULL default '0000-00-00',
110                          datemodified date default NULL,
111                          origincode char(20) default NULL,
112                          PRIMARY KEY  (bibid),
113                          KEY origincode (origincode),
114                          KEY biblionumber (biblionumber)
115                          ) ",
116      marc_blob_subfield => "(
117                              blobidlink bigint(20) NOT NULL auto_increment,
118                              subfieldvalue longtext NOT NULL,
119                              PRIMARY KEY  (blobidlink)
120                             ) ",
121      marc_subfield_structure => "(
122                                   tagfield char(3) NOT NULL default '',
123                                   tagsubfield char(1) NOT NULL default '',
124                                   liblibrarian char(255) NOT NULL default '',
125                                   libopac char(255) NOT NULL default '',
126                                   repeatable tinyint(4) NOT NULL default '0',
127                                   mandatory tinyint(4) NOT NULL default '0',
128                                   kohafield char(40) NOT NULL default '',
129                                   tab tinyint(1),
130                                   PRIMARY KEY  (tagfield,tagsubfield),
131                                   KEY kohafield (kohafield),
132                                   KEY tab (tab)
133                                  )",
134      marc_subfield_table => "(
135                               subfieldid bigint(20) unsigned NOT NULL auto_increment,
136                               bibid bigint(20) unsigned NOT NULL default '0',
137                               tag char(3) NOT NULL default '',
138                               tagorder tinyint(4) NOT NULL default '1',
139                               tag_indicator char(2) NOT NULL default '',
140                               subfieldcode char(1) NOT NULL default '',
141                               subfieldorder tinyint(4) NOT NULL default '1',
142                               subfieldvalue varchar(255) default NULL,
143                               valuebloblink bigint(20) default NULL,
144                               PRIMARY KEY  (subfieldid),
145                               KEY bibid (bibid),
146                               KEY tag (tag),
147                               KEY tag_indicator (tag_indicator),
148                               KEY subfieldorder (subfieldorder),
149                               KEY subfieldcode (subfieldcode),
150                               KEY subfieldvalue (subfieldvalue),
151                               KEY tagorder (tagorder)
152                             )",
153      marc_tag_structure => "(
154                              tagfield char(3) NOT NULL default '',
155                              liblibrarian char(255) NOT NULL default '',
156                              libopac char(255) NOT NULL default '',
157                              repeatable tinyint(4) NOT NULL default '0',
158                              mandatory tinyint(4) NOT NULL default '0',
159                              PRIMARY KEY  (tagfield)
160                             )",
161      marc_word => "(
162                     bibid bigint(20) NOT NULL default '0',
163                     tag char(3) NOT NULL default '',
164                     tagorder tinyint(4) NOT NULL default '1',
165                     subfieldid char(1) NOT NULL default '',
166                     subfieldorder tinyint(4) NOT NULL default '1',
167                     word varchar(255) NOT NULL default '',
168                     sndx_word varchar(255) NOT NULL default '',
169                     KEY bibid (bibid),
170                     KEY tag (tag),
171                     KEY tagorder (tagorder),
172                     KEY subfieldid (subfieldid),
173                     KEY subfieldorder (subfieldorder),
174                     KEY word (word),
175                     KEY sndx_word (sndx_word)
176                    )",
177 );
178
179
180 my %requirefields=(
181     biblio=>{ 'abstract' => 'text' },
182     deletedbiblio=>{ 'abstract' => 'text' },
183     biblioitems=>{ 'lccn' => 'char(25)',
184                 'url' => 'varchar(255)',
185                 'marc' => 'text' },
186     deletedbiblioitems=>{ 'lccn' => 'char(25)',
187                 'url' => 'varchar(255)',
188                 'marc' => 'text' },
189     branchtransfers=>{ 'datearrived' => 'datetime' },
190     statistics=>{'borrowernumber' =>'int(11)'},
191     aqbooksellers=>{'invoicedisc' =>'float(6,4)',
192                      'nocalc' => 'int(11)'},
193     borrowers=>{'userid' => 'char(30)',
194                 'password' => 'char(30)',},
195     aqorders=>{'budgetdate' => 'date'},
196 #added so that reference items are not available for reserves...
197     itemtypes=>{'notforloan' => 'smallint(6)'},
198     systempreferences =>{'explanation' => 'char(80)'},
199 );
200
201 my %dropable_table=(
202                     classification   =>'classification',
203                     multipart        =>'multipart',
204                     multivolume      =>'multivolume',
205                     newitems         =>'newitems',
206                     procedures       =>'procedures',
207                     publisher        =>'publisher',
208                     searchstats      =>'searchstats',
209                     serialissues     =>'serialissues',
210                     );
211
212 # Default system preferences
213 my %defaultprefs=(
214                   'autoMemberNum'=> ['1','1 or else. If 1, Barcode is auto-calculated'],
215                   'acquisitions'=> ['simple','normal or simple : will use acquisition system found in directory acqui.simple or acquisition'],
216                   'template' => ['default','template default name']
217                   );
218
219 #-------------------
220 # Initialize
221 my $dbh = C4::Context->dbh;
222
223 # Start checking
224
225 # Get version of MySQL database engine.
226 my $mysqlversion=`mysqld --version`;
227 $mysqlversion=~/Ver (\S*) /;
228 $mysqlversion=$1;
229 if ($mysqlversion ge '3.23') {
230     print "Could convert to MyISAM database tables...\n";
231 }
232
233 #---------------------------------
234 # Tables
235
236 # Collect all tables into a list
237 $sth=$dbh->prepare("show tables");
238 $sth->execute;
239 while (my ($table) = $sth->fetchrow) {
240     $existingtables{$table}=1;
241 }
242
243 # Now add any missing tables
244 foreach $table ( keys %requiretables ) {
245     print "Checking $table table...\n" if $debug;
246     unless ($existingtables{$table} ) {
247         print "Adding $table table...\n";
248         my $sth=$dbh->prepare(
249                 "create table $table $requiretables{$table}" );
250         $sth->execute;
251         if ($sth->err) {
252                 print "Error : $sth->errstr \n";
253                 $sth->finish;
254         } # if error
255     } # unless exists
256 } # foreach
257
258 # now drop useless tables
259 foreach $table ( keys %dropable_table) {
260     print "Dropping unused tables...\n" if $debug;
261     if ($existingtables{$table} ) {
262         $dbh->do("drop table $table");
263         if ($dbh->err) {
264             print "Error : $dbh->errstr \n";
265         }
266     }
267 }
268 unless ($existingtables{'z3950servers'}) {
269     print "Adding z3950servers table...\n";
270     my $sti=$dbh->prepare("create table z3950servers (
271         host char(255), 
272         port int, 
273         db char(255), 
274         userid char(255), 
275         password char(255), 
276         name text, 
277         id int, 
278         checked smallint, 
279         rank int)");
280     $sti->execute;
281     $sti=$dbh->prepare("insert into z3950servers 
282         values ('z3950.loc.gov', 
283         7090, 
284         'voyager', 
285         '', '', 
286         'Library of Congress', 
287         1, 1, 1)");
288     $sti->execute;
289 }
290
291 #---------------------------------
292 # Columns
293
294 foreach $table ( keys %requirefields ) {
295     print "Check table $table\n" if $debug;
296     $sth=$dbh->prepare("show columns from $table");
297     $sth->execute();
298     undef %types;
299     while ( ($column, $type, $null, $key, $default, $extra) 
300                 = $sth->fetchrow) {
301         $types{$column}=$type;
302     } # while 
303     foreach $column ( keys %{ $requirefields{$table} } )  {
304         print "  Check column $column\n" if $debug;
305         if ( ! $types{$column} ) {
306             # column doesn't exist
307             print "Adding $column field to $table table...\n";
308             $query="alter table $table
309                 add column $column " . $requirefields{$table}->{$column} ;
310             print "Execute: $query\n" if $debug;
311             my $sti=$dbh->prepare($query);
312             $sti->execute;
313             if ($sti->err) {
314                     print "**Error : $sti->errstr \n";
315                     $sti->finish;
316             } # if error
317         } # if column
318     } # foreach column
319 } # foreach table
320
321 # Get list of columns from items table
322 my %itemtypes;
323
324 # FIXME - There's already a $sth in this scope.
325 my $sth=$dbh->prepare("show columns from items");
326 $sth->execute;
327 while (my ($column, $type, $null, $key, $default, $extra) = $sth->fetchrow) {
328     $itemtypes{$column}=$type;
329 }
330
331 unless ($itemtypes{'barcode'} eq 'varchar(20)') {
332     $itemtypes{'barcode'}=~/varchar\((\d+)\)/;
333     my $oldlength=$1;
334     if ($oldlength<20) {
335         print "Setting maximum barcode length to 20 (was $oldlength).\n";
336         my $sti=$dbh->prepare("alter table items change barcode barcode varchar(20) not null");
337         $sti->execute;
338     }
339 }
340
341 # extending the timestamp in branchtransfers...
342 my %branchtransfers;
343
344 # FIXME - There's already a $sth in this scope.
345 my $sth=$dbh->prepare("show columns from branchtransfers");
346 $sth->execute;
347 while (my ($column, $type, $null, $key, $default, $extra) = $sth->fetchrow) {
348     $branchtransfers{$column}=$type;
349 }
350
351 unless ($branchtransfers{'datesent'} eq 'datetime') {
352     print "Setting type of datesent in branchtransfers to datetime.\n";
353     my $sti=$dbh->prepare("alter table branchtransfers change datesent datesent datetime");
354     $sti->execute;
355 }
356
357 unless ($branchtransfers{'datearrived'} eq 'datetime') {
358     print "Setting type of datearrived in branchtransfers to datetime.\n";
359     my $sti=$dbh->prepare("alter table branchtransfers change datearrived datearrived datetime");
360     $sti->execute;
361 }
362
363 # changing the branchcategories table around...
364 my %branchcategories;
365
366 # FIXME - There's already a $sth in this scope.
367 my $sth=$dbh->prepare("show columns from branchcategories");
368 $sth->execute;
369 while (my ($column, $type, $null, $key, $default, $extra) = $sth->fetchrow) {
370     $branchcategories{$column}=$type;
371 }
372
373 unless ($branchcategories{'categorycode'} eq 'varchar(4)') {
374     print "Setting type of categorycode in branchcategories to varchar(4),\n and making the primary key.\n";
375     my $sti=$dbh->prepare("alter table branchcategories change categorycode categorycode varchar(4) not null");
376     $sti->execute;
377     $sti=$dbh->prepare("alter table branchcategories add primary key (categorycode)");
378     $sti->execute;
379 }
380
381 unless ($branchcategories{'categoryname'} eq 'text') {
382     print "Changing branchcode in branchcategories to categoryname text.\n";
383     my $sth=$dbh->prepare("alter table branchcategories change branchcode categoryname text");
384     $sth->execute;
385 }
386
387 unless ($branchcategories{'codedescription'} eq 'text') {
388     print "Replacing branchholding in branchcategories with codedescription text.\n";
389     my $sth=$dbh->prepare("alter table branchcategories change branchholding codedescription text");
390     $sth->execute;
391 }
392
393
394 # Populate systempreferences if it is empty
395
396 foreach $prefitem ( keys %defaultprefs ) {
397     $sth=$dbh->prepare("select value 
398         from systempreferences 
399         where variable=?");
400     $sth->execute($prefitem);
401     unless ($sth->rows) {
402         print "Adding system preference item $prefitem with value " .
403                 $defaultprefs{$prefitem}[0] ."\n";
404         $sti=$dbh->prepare("
405           insert into systempreferences (variable, value,explanation) 
406           values (?,?,?)");
407         $sti->execute($prefitem,$defaultprefs{$prefitem}[0],$defaultprefs{$prefitem}[1]);
408     } # unless
409 } # foreach
410
411
412 $sth->finish;
413
414 exit;
415
416 # $Log$
417 # Revision 1.21  2002/10/14 11:48:59  tipaul
418 # bugfix
419 #
420 # Revision 1.20  2002/10/10 04:49:41  arensb
421 # Added some FIXME comments.
422 #
423 # Revision 1.19  2002/10/05 10:17:17  arensb
424 # Merged with arensb-context branch: use C4::Context->dbh instead of
425 # &C4Connect, and generally prefer C4::Context over C4::Database.
426 #
427 # Revision 1.18.2.2  2002/10/05 06:18:43  arensb
428 # Added a whole mess of FIXME comments.
429 #
430 # Revision 1.18.2.1  2002/10/04 02:46:00  arensb
431 # Use C4::Connect instead of C4::Database, C4::Connect->dbh instead
432 # C4Connect.
433 #
434 # Revision 1.18  2002/09/24 13:50:55  tipaul
435 # long WAS the road to 1.3.0...
436 # coming VERY SOON NOW...
437 # modifying installer and buildrelease to update the DB
438 #
439 # Revision 1.17  2002/09/24 12:57:35  tipaul
440 # long WAS the road to 1.3.0...
441 # coming VERY SOON NOW...
442 # modifying installer and buildrelease to update the DB
443 #
444 # Revision 1.16  2002/07/31 02:34:27  finlayt
445 #
446 # added "notforloan" field to the itemtypes table.
447 #
448 # Revision 1.15  2002/07/20 22:30:06  rangi
449 # Making sure fix makes it into the main branch as well
450 # Fix for bug 69
451 #
452 # Revision 1.14  2002/07/08 16:20:26  tonnesen
453 # Added sessionqueries table and password/userid fields to borrowers table
454 #
455 # Revision 1.13  2002/07/04 18:05:36  tonnesen
456 # bug fix
457 #
458 # Revision 1.12  2002/07/04 16:41:06  tonnesen
459 # Merged changes from rel-1-2.  Abstracted table structure changes by alan.
460 #