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