Added some FIXME comments.
[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                                   PRIMARY KEY  (tagfield,tagsubfield),
130                                   KEY kohafield (kohafield)
131                                  )",
132      marc_subfield_table => "(
133                               subfieldid bigint(20) unsigned NOT NULL auto_increment,
134                               bibid bigint(20) unsigned NOT NULL default '0',
135                               tag char(3) NOT NULL default '',
136                               tagorder tinyint(4) NOT NULL default '1',
137                               tag_indicator char(2) NOT NULL default '',
138                               subfieldcode char(1) NOT NULL default '',
139                               subfieldorder tinyint(4) NOT NULL default '1',
140                               subfieldvalue varchar(255) default NULL,
141                               valuebloblink bigint(20) default NULL,
142                               PRIMARY KEY  (subfieldid),
143                               KEY bibid (bibid),
144                               KEY tag (tag),
145                               KEY tag_indicator (tag_indicator),
146                               KEY subfieldorder (subfieldorder),
147                               KEY subfieldcode (subfieldcode),
148                               KEY subfieldvalue (subfieldvalue),
149                               KEY tagorder (tagorder)
150                             )",
151      marc_tag_structure => "(
152                              tagfield char(3) NOT NULL default '',
153                              liblibrarian char(255) NOT NULL default '',
154                              libopac char(255) NOT NULL default '',
155                              repeatable tinyint(4) NOT NULL default '0',
156                              mandatory tinyint(4) NOT NULL default '0',
157                              PRIMARY KEY  (tagfield)
158                             )",
159      marc_word => "(
160                     bibid bigint(20) NOT NULL default '0',
161                     tag char(3) NOT NULL default '',
162                     tagorder tinyint(4) NOT NULL default '1',
163                     subfieldid char(1) NOT NULL default '',
164                     subfieldorder tinyint(4) NOT NULL default '1',
165                     word varchar(255) NOT NULL default '',
166                     sndx_word varchar(255) NOT NULL default '',
167                     KEY bibid (bibid),
168                     KEY tag (tag),
169                     KEY tagorder (tagorder),
170                     KEY subfieldid (subfieldid),
171                     KEY subfieldorder (subfieldorder),
172                     KEY word (word),
173                     KEY sndx_word (sndx_word)
174                    )",
175 );
176
177
178 my %requirefields=(
179     biblio=>{ 'abstract' => 'text' },
180     deletedbiblio=>{ 'abstract' => 'text' },
181     biblioitems=>{ 'lccn' => 'char(25)',
182                 'url' => 'varchar(255)',
183                 'marc' => 'text' },
184     deletedbiblioitems=>{ 'lccn' => 'char(25)',
185                 'url' => 'varchar(255)',
186                 'marc' => 'text' },
187     branchtransfers=>{ 'datearrived' => 'datetime' },
188     statistics=>{'borrowernumber' =>'int(11)'},
189     aqbooksellers=>{'invoicedisc' =>'float(6,4)',
190                      'nocalc' => 'int(11)'},
191     borrowers=>{'userid' => 'char(30)',
192                 'password' => 'char(30)',},
193     aqorders=>{'budgetdate' => 'date'},
194 #added so that reference items are not available for reserves...
195     itemtypes=>{'notforloan' => 'smallint(6)'},
196     systempreferences =>{'explanation' => 'char(80)'},
197 );
198
199 my %dropable_table=(
200                     classification   =>'classification',
201                     multipart        =>'multipart',
202                     multivolume      =>'multivolume',
203                     newitems         =>'newitems',
204                     procedures       =>'procedures',
205                     publisher        =>'publisher',
206                     searchstats      =>'searchstats',
207                     serialissues     =>'serialissues',
208                     );
209
210 # Default system preferences
211 my %defaultprefs=(
212                   'autoMemberNum'=> ['1','1 or else. If 1, Barcode is auto-calculated'],
213                   'acquisitions'=> ['simple','normal or simple : will use acquisition system found in directory acqui.simple or acquisition'],
214                   'template' => ['default','template default name']
215                   );
216
217 #-------------------
218 # Initialize
219 my $dbh = C4::Context->dbh;
220
221 # Start checking
222
223 # Get version of MySQL database engine.
224 my $mysqlversion=`mysqld --version`;
225 $mysqlversion=~/Ver (\S*) /;
226 $mysqlversion=$1;
227 if ($mysqlversion ge '3.23') {
228     print "Could convert to MyISAM database tables...\n";
229 }
230
231 #---------------------------------
232 # Tables
233
234 # Collect all tables into a list
235 $sth=$dbh->prepare("show tables");
236 $sth->execute;
237 while (my ($table) = $sth->fetchrow) {
238     $existingtables{$table}=1;
239 }
240
241 # Now add any missing tables
242 foreach $table ( keys %requiretables ) {
243     print "Checking $table table...\n" if $debug;
244     unless ($existingtables{$table} ) {
245         print "Adding $table table...\n";
246         my $sth=$dbh->prepare(
247                 "create table $table $requiretables{$table}" );
248         $sth->execute;
249         if ($sth->err) {
250                 print "Error : $sth->errstr \n";
251                 $sth->finish;
252         } # if error
253     } # unless exists
254 } # foreach
255
256 # now drop useless tables
257 foreach $table ( keys %dropable_table) {
258     print "Dropping unused tables...\n" if $debug;
259     if ($existingtables{$table} ) {
260         $dbh->do("drop table $table");
261         if ($dbh->err) {
262             print "Error : $dbh->errstr \n";
263         }
264     }
265 }
266 unless ($existingtables{'z3950servers'}) {
267     print "Adding z3950servers table...\n";
268     my $sti=$dbh->prepare("create table z3950servers (
269         host char(255), 
270         port int, 
271         db char(255), 
272         userid char(255), 
273         password char(255), 
274         name text, 
275         id int, 
276         checked smallint, 
277         rank int)");
278     $sti->execute;
279     $sti=$dbh->prepare("insert into z3950servers 
280         values ('z3950.loc.gov', 
281         7090, 
282         'voyager', 
283         '', '', 
284         'Library of Congress', 
285         1, 1, 1)");
286     $sti->execute;
287 }
288
289 #---------------------------------
290 # Columns
291
292 foreach $table ( keys %requirefields ) {
293     print "Check table $table\n" if $debug;
294     $sth=$dbh->prepare("show columns from $table");
295     $sth->execute();
296     undef %types;
297     while ( ($column, $type, $null, $key, $default, $extra) 
298                 = $sth->fetchrow) {
299         $types{$column}=$type;
300     } # while 
301     foreach $column ( keys %{ $requirefields{$table} } )  {
302         print "  Check column $column\n" if $debug;
303         if ( ! $types{$column} ) {
304             # column doesn't exist
305             print "Adding $column field to $table table...\n";
306             $query="alter table $table
307                 add column $column " . $requirefields{$table}->{$column} ;
308             print "Execute: $query\n" if $debug;
309             my $sti=$dbh->prepare($query);
310             $sti->execute;
311             if ($sti->err) {
312                     print "**Error : $sti->errstr \n";
313                     $sti->finish;
314             } # if error
315         } # if column
316     } # foreach column
317 } # foreach table
318
319 # Get list of columns from items table
320 my %itemtypes;
321
322 # FIXME - There's already a $sth in this scope.
323 my $sth=$dbh->prepare("show columns from items");
324 $sth->execute;
325 while (my ($column, $type, $null, $key, $default, $extra) = $sth->fetchrow) {
326     $itemtypes{$column}=$type;
327 }
328
329 unless ($itemtypes{'barcode'} eq 'varchar(20)') {
330     $itemtypes{'barcode'}=~/varchar\((\d+)\)/;
331     my $oldlength=$1;
332     if ($oldlength<20) {
333         print "Setting maximum barcode length to 20 (was $oldlength).\n";
334         my $sti=$dbh->prepare("alter table items change barcode barcode varchar(20) not null");
335         $sti->execute;
336     }
337 }
338
339 # extending the timestamp in branchtransfers...
340 my %branchtransfers;
341
342 # FIXME - There's already a $sth in this scope.
343 my $sth=$dbh->prepare("show columns from branchtransfers");
344 $sth->execute;
345 while (my ($column, $type, $null, $key, $default, $extra) = $sth->fetchrow) {
346     $branchtransfers{$column}=$type;
347 }
348
349 unless ($branchtransfers{'datesent'} eq 'datetime') {
350     print "Setting type of datesent in branchtransfers to datetime.\n";
351     my $sti=$dbh->prepare("alter table branchtransfers change datesent datesent datetime");
352     $sti->execute;
353 }
354
355 unless ($branchtransfers{'datearrived'} eq 'datetime') {
356     print "Setting type of datearrived in branchtransfers to datetime.\n";
357     my $sti=$dbh->prepare("alter table branchtransfers change datearrived datearrived datetime");
358     $sti->execute;
359 }
360
361 # changing the branchcategories table around...
362 my %branchcategories;
363
364 # FIXME - There's already a $sth in this scope.
365 my $sth=$dbh->prepare("show columns from branchcategories");
366 $sth->execute;
367 while (my ($column, $type, $null, $key, $default, $extra) = $sth->fetchrow) {
368     $branchcategories{$column}=$type;
369 }
370
371 unless ($branchcategories{'categorycode'} eq 'varchar(4)') {
372     print "Setting type of categorycode in branchcategories to varchar(4),\n and making the primary key.\n";
373     my $sti=$dbh->prepare("alter table branchcategories change categorycode categorycode varchar(4) not null");
374     $sti->execute;
375     $sti=$dbh->prepare("alter table branchcategories add primary key (categorycode)");
376     $sti->execute;
377 }
378
379 unless ($branchcategories{'categoryname'} eq 'text') {
380     print "Changing branchcode in branchcategories to categoryname text.\n";
381     my $sth=$dbh->prepare("alter table branchcategories change branchcode categoryname text");
382     $sth->execute;
383 }
384
385 unless ($branchcategories{'codedescription'} eq 'text') {
386     print "Replacing branchholding in branchcategories with codedescription text.\n";
387     my $sth=$dbh->prepare("alter table branchcategories change branchholding codedescription text");
388     $sth->execute;
389 }
390
391
392 # Populate systempreferences if it is empty
393
394 foreach $prefitem ( keys %defaultprefs ) {
395     $sth=$dbh->prepare("select value 
396         from systempreferences 
397         where variable=?");
398     $sth->execute($prefitem);
399     unless ($sth->rows) {
400         print "Adding system preference item $prefitem with value " .
401                 $defaultprefs{$prefitem}[0] ."\n";
402         $sti=$dbh->prepare("
403           insert into systempreferences (variable, value,explanation) 
404           values (?,?,?)");
405         $sti->execute($prefitem,$defaultprefs{$prefitem}[0],$defaultprefs{$prefitem}[1]);
406     } # unless
407 } # foreach
408
409
410 $sth->finish;
411
412 exit;
413
414 # $Log$
415 # Revision 1.20  2002/10/10 04:49:41  arensb
416 # Added some FIXME comments.
417 #
418 # Revision 1.19  2002/10/05 10:17:17  arensb
419 # Merged with arensb-context branch: use C4::Context->dbh instead of
420 # &C4Connect, and generally prefer C4::Context over C4::Database.
421 #
422 # Revision 1.18.2.2  2002/10/05 06:18:43  arensb
423 # Added a whole mess of FIXME comments.
424 #
425 # Revision 1.18.2.1  2002/10/04 02:46:00  arensb
426 # Use C4::Connect instead of C4::Database, C4::Connect->dbh instead
427 # C4Connect.
428 #
429 # Revision 1.18  2002/09/24 13:50:55  tipaul
430 # long WAS the road to 1.3.0...
431 # coming VERY SOON NOW...
432 # modifying installer and buildrelease to update the DB
433 #
434 # Revision 1.17  2002/09/24 12:57:35  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.16  2002/07/31 02:34:27  finlayt
440 #
441 # added "notforloan" field to the itemtypes table.
442 #
443 # Revision 1.15  2002/07/20 22:30:06  rangi
444 # Making sure fix makes it into the main branch as well
445 # Fix for bug 69
446 #
447 # Revision 1.14  2002/07/08 16:20:26  tonnesen
448 # Added sessionqueries table and password/userid fields to borrowers table
449 #
450 # Revision 1.13  2002/07/04 18:05:36  tonnesen
451 # bug fix
452 #
453 # Revision 1.12  2002/07/04 16:41:06  tonnesen
454 # Merged changes from rel-1-2.  Abstracted table structure changes by alan.
455 #