adding table issuingrules (previously called categoryitem
[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
24 # FIXME - The user might be installing a new database, so can't rely
25 # on /etc/koha.conf anyway.
26
27 my $debug = 0;
28
29 my (
30     $sth, $sti,
31     $query,
32     %existingtables,    # tables already in database
33     %types,
34     $table,
35     $column,
36     $type, $null, $key, $default, $extra,
37     $prefitem,          # preference item in systempreferences table
38 );
39
40 my $dbh = C4::Context->dbh;
41 print "connected to your DB. Checking & modifying it\n";
42
43 #-------------------
44 # Defines
45
46 # Tables to add if they don't exist
47 my %requiretables = (
48     shelfcontents => "( shelfnumber int not null,
49                                                         itemnumber int not null,
50                                                         flags int)",
51     bookshelf => "( shelfnumber int auto_increment primary key,
52                                                 shelfname char(255))",
53     z3950queue => "( id int auto_increment primary key,
54                                                 term text,
55                                                 type char(10),
56                                                 startdate int,
57                                                 enddate int,
58                                                 done smallint,
59                                                 results longblob,
60                                                 numrecords int,
61                                                 servers text,
62                                                 identifier char(30))",
63     z3950results => "( id int auto_increment primary key,
64                                                 queryid int,
65                                                 server char(255),
66                                                 startdate int,
67                                                 enddate int,
68                                                 results longblob,
69                                                 numrecords int,
70                                                 numdownloaded int,
71                                                 highestseen int,
72                                                 active smallint)",
73     branchrelations => "( branchcode varchar(4),
74                                                         categorycode varchar(4))",
75     websites => "( websitenumber int(11) NOT NULL auto_increment,
76                                                 biblionumber int(11) NOT NULL default '0',
77                                                 title text,
78                                                 description text,
79                                                 url varchar(255),
80                                                 PRIMARY KEY (websitenumber) )",
81     marcrecorddone => "( isbn char(40),
82                                                                 issn char(40),
83                                                                 lccn char(40),
84                                                                 controlnumber char(40))",
85     uploadedmarc => "( id int(11) NOT NULL auto_increment PRIMARY KEY,
86                                                         marc longblob,
87                                                         hidden smallint(6) default NULL,
88                                                         name varchar(255) default NULL)",
89     ethnicity => "( code varchar(10) NOT NULL default '',
90                                         name varchar(255) default NULL,
91                                         PRIMARY KEY  (code)   )",
92     sessions => "( sessionID varchar(255) NOT NULL default '',
93                                                 userid varchar(255) default NULL,
94                                                 ip varchar(16) default NULL,
95                                                 lasttime int,
96                                                 PRIMARY KEY (sessionID)   )",
97     sessionqueries => "( sessionID varchar(255) NOT NULL default '',
98                                                                 userid char(100) NOT NULL default '',
99                                                                 ip char(18) NOT NULL default '',
100                                                                 url text NOT NULL default ''  )",
101     bibliothesaurus => "( id bigint(20) NOT NULL auto_increment,
102                                                         freelib char(255) NOT NULL default '',
103                                                         stdlib char(255) NOT NULL default '',
104                                                         category char(10) NOT NULL default '',
105                                                         level tinyint(4) NOT NULL default '1',
106                                                         hierarchy char(80) NOT NULL default '',
107                                                         father char(80) NOT NULL default '',
108                                                         PRIMARY KEY  (id),
109                                                         KEY freelib (freelib),
110                                                         KEY stdlib (stdlib),
111                                                         KEY category (category),
112                                                         KEY hierarchy (hierarchy)
113                                                         )",
114     marc_biblio => "(
115                                                 bibid bigint(20) unsigned NOT NULL auto_increment,
116                                                 biblionumber int(11) NOT NULL default '0',
117                                                 datecreated date NOT NULL default '0000-00-00',
118                                                 datemodified date default NULL,
119                                                 origincode char(20) default NULL,
120                                                 PRIMARY KEY  (bibid),
121                                                 KEY origincode (origincode),
122                                                 KEY biblionumber (biblionumber)
123                                                 ) ",
124     marc_blob_subfield => "(
125                                         blobidlink bigint(20) NOT NULL auto_increment,
126                                         subfieldvalue longtext NOT NULL,
127                                         PRIMARY KEY  (blobidlink)
128                                         ) ",
129     marc_subfield_structure => "(
130                                                 tagfield char(3) NOT NULL default '',
131                                                 tagsubfield char(1) NOT NULL default '',
132                                                 liblibrarian char(255) NOT NULL default '',
133                                                 libopac char(255) NOT NULL default '',
134                                                 repeatable tinyint(4) NOT NULL default '0',
135                                                 mandatory tinyint(4) NOT NULL default '0',
136                                                 kohafield char(40)  default NULL,
137                                                 tab tinyint(1) default NULL,
138                                                 authorised_value char(10) default NULL,
139                                                 thesaurus_category char(10) default NULL,
140                                                 value_builder char(80) default NULL,
141                                                 PRIMARY KEY  (tagfield,tagsubfield),
142                                                 KEY kohafield (kohafield),
143                                                 KEY tab (tab)
144                                                 )",
145     marc_subfield_table => "(
146                                                 subfieldid bigint(20) unsigned NOT NULL auto_increment,
147                                                 bibid bigint(20) unsigned NOT NULL default '0',
148                                                 tag char(3) NOT NULL default '',
149                                                 tagorder tinyint(4) NOT NULL default '1',
150                                                 tag_indicator char(2) NOT NULL default '',
151                                                 subfieldcode char(1) NOT NULL default '',
152                                                 subfieldorder tinyint(4) NOT NULL default '1',
153                                                 subfieldvalue varchar(255) default NULL,
154                                                 valuebloblink bigint(20) default NULL,
155                                                 PRIMARY KEY  (subfieldid),
156                                                 KEY bibid (bibid),
157                                                 KEY tag (tag),
158                                                 KEY tag_indicator (tag_indicator),
159                                                 KEY subfieldorder (subfieldorder),
160                                                 KEY subfieldcode (subfieldcode),
161                                                 KEY subfieldvalue (subfieldvalue),
162                                                 KEY tagorder (tagorder)
163                                         )",
164     marc_tag_structure => "(
165                                         tagfield char(3) NOT NULL default '',
166                                         liblibrarian char(255) NOT NULL default '',
167                                         libopac char(255) NOT NULL default '',
168                                         repeatable tinyint(4) NOT NULL default '0',
169                                         mandatory tinyint(4) NOT NULL default '0',
170                                         authorised_value char(10) default NULL,
171                                         PRIMARY KEY  (tagfield)
172                                         )",
173     marc_word => "(
174                                 bibid bigint(20) NOT NULL default '0',
175                                 tag char(3) NOT NULL default '',
176                                 tagorder tinyint(4) NOT NULL default '1',
177                                 subfieldid char(1) NOT NULL default '',
178                                 subfieldorder tinyint(4) NOT NULL default '1',
179                                 word varchar(255) NOT NULL default '',
180                                 sndx_word varchar(255) NOT NULL default '',
181                                 KEY bibid (bibid),
182                                 KEY tag (tag),
183                                 KEY tagorder (tagorder),
184                                 KEY subfieldid (subfieldid),
185                                 KEY subfieldorder (subfieldorder),
186                                 KEY word (word),
187                                 KEY sndx_word (sndx_word)
188                         )",
189     marc_breeding => "(  id bigint(20) NOT NULL auto_increment,
190                                 file varchar(80) NOT NULL default '',
191                                 isbn varchar(10) NOT NULL default '',
192                                 title varchar(128) default NULL,
193                                 author varchar(80) default NULL,
194                                 marc text NOT NULL,
195                                 encoding varchar(40) default NULL,
196                                 PRIMARY KEY  (id),
197                                 KEY title (title),
198                                 KEY isbn (isbn)
199                         )",
200     authorised_values => "(id int(11) NOT NULL auto_increment,
201                                 category char(10) NOT NULL default '',
202                                 authorised_value char(80) NOT NULL default '',
203                                 lib char(80) NULL,
204                                 PRIMARY KEY  (id),
205                                 KEY name (category)
206                         )",
207     userflags => "( bit int(11) NOT NULL default '0',
208                                 flag char(30), flagdesc char(255),
209                                 defaulton int(11)
210                         )",
211 );
212
213 my %requirefields = (
214     biblio        => { 'abstract' => 'text' },
215     deletedbiblio => { 'abstract' => 'text', 'marc' => 'blob' },
216     deleteditems => { 'marc' => 'blob', 'paidfor' => 'text' },
217     biblioitems   => {
218         'lccn' => 'char(25)',
219         'url'  => 'varchar(255)',
220         'marc' => 'text'
221     },
222     deletedbiblioitems => {
223         'lccn' => 'char(25)',
224         'url'  => 'varchar(255)',
225         'marc' => 'text'
226     },
227     branchtransfers => { 'datearrived'    => 'datetime' },
228     statistics      => { 'borrowernumber' => 'int(11)' },
229     aqbooksellers   => {
230         'invoicedisc' => 'float(6,4)',
231         'nocalc'      => 'int(11)'
232     },
233     borrowers => {
234         'userid'        => 'char(30)',
235         'password'      => 'char(30)',
236         'flags'         => 'int(11)',
237         'textmessaging' => 'varchar(30)',
238            'zipcode' => 'varchar(25)',
239                         'homezipcode' => 'varchar(25)',
240     },
241     aqorders => { 'budgetdate' => 'date' },
242     aqbudget => {'aqbudgetid' => 'tinyint(4) auto_increment primary key'},
243     items => {'paidfor' => 'text'},
244
245     #added so that reference items are not available for reserves...
246     itemtypes         => { 'notforloan'  => 'smallint(6)' },
247     systempreferences => { 'explanation' => 'char(80)',
248                            'type' => 'char(20)',
249                            'options' => 'text' },
250     z3950servers      => { 'syntax'      => 'char(80)' },
251     marc_subfield_structure =>{'seealso'  => 'char(255)'},
252     bookshelf => {'owner' => 'char(80)',
253                                         'category' => 'char(1)',
254                                 },
255 );
256
257 my %dropable_table = (
258     classification => 'classification',
259     multipart      => 'multipart',
260     multivolume    => 'multivolume',
261     newitems       => 'newitems',
262     procedures     => 'procedures',
263     publisher      => 'publisher',
264     searchstats    => 'searchstats',
265     serialissues   => 'serialissues',
266 );
267
268 # the other hash contains other actions that can't be done elsewhere. they are done
269 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
270
271 # The tabledata hash contains data that should be in the tables.
272 # The uniquefieldrequired hash entry is used to determine which (if any) fields
273 # must not exist in the table for this row to be inserted.  If the
274 # uniquefieldrequired entry is already in the table, the existing data is not
275 # modified, unless the forceupdate hash entry is also set.  Fields in the
276 # anonymous "forceupdate" hash will be forced to be updated to the default
277 # values given in the %tabledata hash.
278
279 my %tabledata = (
280     userflags => [
281         {
282             uniquefieldrequired => 'bit',
283             bit                 => 0,
284             flag                => 'superlibrarian',
285             flagdesc            => 'Access to all librarian functions',
286             defaulton           => 0
287         },
288         {
289             uniquefieldrequired => 'bit',
290             bit                 => 1,
291             flag                => 'circulate',
292             flagdesc            => 'Circulate books',
293             defaulton           => 0
294         },
295         {
296             uniquefieldrequired => 'bit',
297             bit                 => 2,
298             flag                => 'catalogue',
299             flagdesc            => 'View Catalogue (Librarian Interface)',
300             defaulton           => 0
301         },
302         {
303             uniquefieldrequired => 'bit',
304             bit                 => 3,
305             flag                => 'parameters',
306             flagdesc            => 'Set Koha system paramters',
307             defaulton           => 0
308         },
309         {
310             uniquefieldrequired => 'bit',
311             bit                 => 4,
312             flag                => 'borrowers',
313             flagdesc            => 'Add or modify borrowers',
314             defaulton           => 0
315         },
316         {
317             uniquefieldrequired => 'bit',
318             bit                 => 5,
319             flag                => 'permissions',
320             flagdesc            => 'Set user permissions',
321             defaulton           => 0
322         },
323         {
324             uniquefieldrequired => 'bit',
325             bit                 => 6,
326             flag                => 'reserveforothers',
327             flagdesc            => 'Reserve books for patrons',
328             defaulton           => 0
329         },
330         {
331             uniquefieldrequired => 'bit',
332             bit                 => 7,
333             flag                => 'borrow',
334             flagdesc            => 'Borrow books',
335             defaulton           => 1
336         },
337         {
338             uniquefieldrequired => 'bit',
339             bit                 => 8,
340             flag                => 'reserveforself',
341             flagdesc            => 'Reserve books for self',
342             defaulton           => 0
343         },
344         {
345             uniquefieldrequired => 'bit',
346             bit                 => 9,
347             flag                => 'editcatalogue',
348             flagdesc  => 'Edit Catalogue (Modify bibliographic/holdings data)',
349             defaulton => 0
350         },
351         {
352             uniquefieldrequired => 'bit',
353             bit                 => 10,
354             flag                => 'updatecharges',
355             flagdesc            => 'Update borrower charges',
356             defaulton           => 0
357         },
358     ],
359     systempreferences => [
360         {
361             uniquefieldrequired => 'variable',
362             forceupdate         => { 'explanation' => 1,
363                                      'type' => 1 },
364             variable            => 'LibraryName',
365             value               => '<i><b>Koha<br/>Free Software ILS<br/><br/></b>Koha : a gift, a contribution<br/> in Maori</i>',
366             explanation         => 'Library name as shown on main opac page',
367             type                => ''
368
369         },
370         {
371             uniquefieldrequired => 'variable',
372             forceupdate         => { 'explanation' => 1,
373                                      'type' => 1 },
374             variable            => 'autoMemberNum',
375             value               => '1',
376             explanation         => 'Member number is auto-calculated',
377             type                => 'YesNo'
378
379         },
380         {
381             uniquefieldrequired => 'variable',
382             forceupdate         => { 'explanation' => 1,
383                                      'type' => 1,
384                                      'options' => 1 },
385             variable            => 'acquisitions',
386             value               => 'normal',
387             explanation         =>
388 'Normal, budget-based acquisitions, or Simple bibliographic-data acquisitions',
389             type                => 'Choice',
390             options             => 'simple|normal'
391         },
392         {
393             uniquefieldrequired => 'variable',
394             forceupdate         => { 'explanation' => 1,
395                                      'type' => 1,
396                                      'options' => 1 },
397             variable            => 'dateformat',
398             value               => 'metric',
399             explanation         =>
400             'date format (us mm/dd/yyyy, metric dd/mm/yyy, ISO yyyy/mm/dd)',
401             type                => 'Choice',
402             options             => 'metric|us|iso'
403         },
404         {
405             uniquefieldrequired => 'variable',
406             variable            => 'template',
407             forceupdate         => { 'explanation' => 1,
408                                      'type' => 1 },
409             value               => 'default',
410             explanation         => 'Preference order for intranet interface templates',
411             type                => 'Themes'
412         },
413         {
414             uniquefieldrequired => 'variable',
415             variable            => 'autoBarcode',
416             forceupdate         => { 'explanation' => 1,
417                                      'type' => 1 },
418             value               => 'yes',
419             explanation         => 'Barcode is auto-calculated',
420             type                => 'YesNo'
421         },
422         {
423             uniquefieldrequired => 'variable',
424             variable            => 'insecure',
425             forceupdate         => { 'explanation' => 1,
426                                      'type' => 1 },
427             value               => 'no',
428             explanation         =>
429 'If YES, no auth at all is needed. Be careful if you set this to yes!',
430             type                => 'YesNo'
431         },
432         {
433             uniquefieldrequired => 'variable',
434             variable            => 'authoritysep',
435             forceupdate         => { 'explanation' => 1,
436                                      'type' => 1,
437                                      'options' => 1 },
438             value               => '--',
439             explanation         =>
440             'the separator used in authority/thesaurus. Usually --',
441             type                => 'free',
442             options             => '10'
443         },
444         {
445             uniquefieldrequired => 'variable',
446             variable            => 'opaclanguages',
447             forceupdate         => { 'explanation' => 1,
448                                      'type' => 1 },
449             value               => 'en',
450             explanation         => 'Set the preferred order for translations.  The top language will be tried first.',
451             type                => 'Languages'
452         },
453         {
454             uniquefieldrequired => 'variable',
455             variable            => 'opacthemes',
456             forceupdate         => { 'explanation' => 1,
457                                      'type' => 1 },
458             value               => 'default',
459             explanation         => 'Set the preferred order for themes.  The top theme will be tried first.',
460             type                => 'Themes'
461         },
462         {
463             uniquefieldrequired => 'variable',
464             variable            => 'timeout',
465             forceupdate         => { 'explanation' => 1,
466                                      'type' => 1 },
467             value               => '1200',
468             explanation         => 'Inactivity timeout for cookies authentication (in seconds)',
469             type                => 'Integer'
470         },
471         {
472             uniquefieldrequired => 'variable',
473             variable            => 'marc',
474             forceupdate         => { 'explanation' => 1,
475                                      'type' => 1 },
476             value               => 'yes',
477             explanation         => 'Turn on MARC support',
478             type                => 'YesNo'
479         },
480         {
481             uniquefieldrequired => 'variable',
482             variable            => 'marcflavour',
483             forceupdate         => { 'explanation' => 1,
484                                      'type' => 1,
485                                      'options' => 1},
486             value               => 'MARC21',
487             explanation         =>
488             'your MARC flavor (MARC21 or UNIMARC) used for character encoding',
489             type                => 'Choice',
490             options             => 'MARC21|UNIMARC'
491         },
492         {
493             uniquefieldrequired => 'variable',
494             variable            => 'checkdigit',
495             value               => 'none',
496             forceupdate         => { 'explanation' => 1,
497                                      'type' => 1,
498                                      'options' => 1},
499             explanation         => 'Validity checks on membership number: none or "Katipo" style checks',
500             type                => 'Choice',
501             options             => 'none|katipo'
502         },
503         {
504             uniquefieldrequired => 'variable',
505             variable            => 'maxoutstanding',
506             forceupdate         => { 'explanation' => 1,
507                                      'type' => 1 },
508             value               => '5',
509             explanation         =>
510             'maximum amount withstanding to be able make reserves ',
511             type                => 'Integer'
512         },
513         {
514             uniquefieldrequired => 'variable',
515             variable            => 'maxreserves',
516             forceupdate         => { 'explanation' => 1,
517                                      'type' => 1 },
518             value               => '5',
519             explanation         =>
520             'maximum number of reserves a member can make',
521             type                => 'Integer'
522
523         },
524         {
525             uniquefieldrequired => 'variable',
526             variable            => 'noissuescharge',
527             forceupdate         => { 'explanation' => 1,
528                                      'type' => 1 },
529             value               => '5',
530             explanation         =>
531             'maximum amount withstanding to be able to check out an item',
532             type                => 'Integer'
533
534         },
535         {
536             uniquefieldrequired => 'variable',
537             variable            => 'KohaAdminEmailAddress',
538             forceupdate         => { 'explanation' => 1,
539                                      'type' => 1 },
540             value               => 'your.mail@here',
541             explanation => 'the email address where borrowers modifs are sent',
542             type                => 'free'
543         },
544         {
545             uniquefieldrequired => 'variable',
546             variable            => 'gist',
547             forceupdate         => { 'explanation' => 1,
548                                      'type' => 1 },
549             value               => '0.125',
550             explanation => 'the gist rate. NOT in %, but in numeric form (0.12 for 12%)',
551             type                => 'free'
552         },
553         {
554             uniquefieldrequired => 'variable',
555             variable            => 'ldapserver',
556             forceupdate         => { 'explanation' => 1,
557                                      'type' => 1 },
558             value               => '',
559             explanation => 'your ldap server',
560             type                => 'free'
561         },
562         {
563             uniquefieldrequired => 'variable',
564             variable            => 'ldapinfos',
565             forceupdate         => { 'explanation' => 1,
566                                      'type' => 1 },
567             value               => '',
568             explanation => 'ldap info. The ldap will be used in dn : uid=xxx, <ldapinfos>',
569             type                => 'free'
570         },
571         {
572             uniquefieldrequired => 'variable',
573             variable            => 'printcirculationslips',
574             forceupdate         => { 'explanation' => 1,
575                                      'type' => 1 },
576             value               => '0',
577             explanation => 'if set to 1, print circulation slips. If set to 0, don\'t',
578             type                => 'free'
579         },
580     ],
581
582 );
583
584 my %fielddefinitions = (
585     printers => [
586         {
587             field   => 'printername',
588             type    => 'char(40)',
589             null    => '',
590             key     => 'PRI',
591             default => ''
592         },
593     ],
594     aqbookfund => [
595         {
596             field   => 'bookfundid',
597             type    => 'char(5)',
598             null    => '',
599             key     => 'PRI',
600             default => ''
601         },
602     ],
603     aqbudget => [
604         {
605             field   => 'aqbudgetid',
606             type    => 'tinyint(4)',
607             null    => '',
608             key     => 'PRI',
609                   default =>'',
610             extra => 'auto_increment'
611         },
612     ],
613     z3950servers => [
614         {
615             field   => 'id',
616             type    => 'int',
617             null    => '',
618             key     => 'PRI',
619             default => '',
620             extra   => 'auto_increment'
621         },
622     ],
623         marc_breeding => [
624         {
625             field   => 'z3950random',
626             type    => 'varchar(40)',
627             null    => 'NULL',
628             key     => '',
629             default => '',
630             extra   => ''
631         },
632         {
633             field   => 'encoding',
634             type    => 'varchar(40)',
635             null    => '',
636             key     => '',
637             default => '',
638             extra   => ''
639         },
640     ],
641 );
642
643 #-------------------
644 # Initialize
645
646 # Start checking
647
648 # Get version of MySQL database engine.
649 my $mysqlversion = `mysqld --version`;
650 $mysqlversion =~ /Ver (\S*) /;
651 $mysqlversion = $1;
652 if ( $mysqlversion ge '3.23' ) {
653     print "Could convert to MyISAM database tables...\n";
654 }
655
656 #---------------------------------
657 # Tables
658
659 # Collect all tables into a list
660 $sth = $dbh->prepare("show tables");
661 $sth->execute;
662 while ( my ($table) = $sth->fetchrow ) {
663     $existingtables{$table} = 1;
664 }
665
666
667 # Now add any missing tables
668 foreach $table ( keys %requiretables ) {
669     unless ( $existingtables{$table} ) {
670         print "Adding $table table...\n";
671         my $sth = $dbh->prepare("create table $table $requiretables{$table}");
672         $sth->execute;
673         if ( $sth->err ) {
674             print "Error : $sth->errstr \n";
675             $sth->finish;
676         }    # if error
677     }    # unless exists
678 }    # foreach
679
680 # now drop useless tables
681 foreach $table ( keys %dropable_table ) {
682         if ( $existingtables{$table} ) {
683                 print "Dropping unused table $table\n" if $debug;
684                 $dbh->do("drop table $table");
685                 if ( $dbh->err ) {
686                         print "Error : $dbh->errstr \n";
687                 }
688         }
689 }
690 unless ( $existingtables{'z3950servers'} ) {
691         #MJR: added syntax entries to close bug 624
692     print "Adding z3950servers table...\n";
693     my $sti = $dbh->prepare( "create table z3950servers (
694                                                                                 host char(255),
695                                                                                 port int,
696                                                                                 db char(255),
697                                                                                 userid char(255),
698                                                                                 password char(255),
699                                                                                 name text,
700                                                                                 id int,
701                                                                                 checked smallint,
702                                                                                 rank int,
703                                                                                 syntax char(80))"
704     );
705     $sti->execute;
706     $sti = $dbh->prepare( "insert into z3950servers
707                                                                 values ('z3950.loc.gov',
708                                                                 7090,
709                                                                 'voyager',
710                                                                 '', '',
711                                                                 'Library of Congress',
712                                                                 1, 1, 1, 'USMARC')"
713     );
714     $sti->execute;
715 }
716 unless ( $existingtables{'issuingrules'} ) {
717         $dbh->do("alter table categoryitem rename issuingrules");
718         print "renaming categoryitem\n";
719 }
720
721
722 #---------------------------------
723 # Columns
724
725 foreach $table ( keys %requirefields ) {
726     print "Check table $table\n" if $debug;
727     $sth = $dbh->prepare("show columns from $table");
728     $sth->execute();
729     undef %types;
730     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
731     {
732         $types{$column} = $type;
733     }    # while
734     foreach $column ( keys %{ $requirefields{$table} } ) {
735         print "  Check column $column  [$types{$column}]\n" if $debug;
736         if ( !$types{$column} ) {
737
738             # column doesn't exist
739             print "Adding $column field to $table table...\n";
740             $query = "alter table $table
741                         add column $column " . $requirefields{$table}->{$column};
742             print "Execute: $query\n" if $debug;
743             my $sti = $dbh->prepare($query);
744             $sti->execute;
745             if ( $sti->err ) {
746                 print "**Error : $sti->errstr \n";
747                 $sti->finish;
748             }    # if error
749         }    # if column
750     }    # foreach column
751 }    # foreach table
752
753 foreach $table ( keys %fielddefinitions ) {
754         print "Check table $table\n" if $debug;
755         $sth = $dbh->prepare("show columns from $table");
756         $sth->execute();
757         my $definitions;
758         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
759         {
760                 $definitions->{$column}->{type}    = $type;
761                 $definitions->{$column}->{null}    = $null;
762                 $definitions->{$column}->{key}     = $key;
763                 $definitions->{$column}->{default} = $default;
764                 $definitions->{$column}->{extra}   = $extra;
765         }    # while
766         my $fieldrow = $fielddefinitions{$table};
767         foreach my $row (@$fieldrow) {
768                 my $field   = $row->{field};
769                 my $type    = $row->{type};
770                 my $null    = $row->{null};
771                 my $key     = $row->{key};
772                 my $default = $row->{default};
773                 $default="''" unless $default;
774                 my $extra   = $row->{extra};
775                 my $def     = $definitions->{$field};
776                 unless ( $type eq $def->{type}
777                         && $null eq $def->{null}
778                         && $key eq $def->{key}
779                         && $default eq $def->{default}
780                         && $extra eq $def->{extra} )
781                 {
782
783                         if ( $null eq '' ) {
784                                 $null = 'NOT NULL';
785                         }
786                         if ( $key eq 'PRI' ) {
787                                 $key = 'PRIMARY KEY';
788                         }
789                         unless ( $extra eq 'auto_increment' ) {
790                                 $extra = '';
791                         }
792                         # if it's a new column use "add", if it's an old one, use "change".
793                         my $action;
794                         if ($definitions->{$field}->{type}) {
795                                 $action="change $field"
796                         } else {
797                                 $action="add";
798                         }
799 # if it's a primary key, drop the previous pk, before altering the table
800                         my $sth;
801                         if ($key ne 'PRIMARY KEY') {
802                                 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
803                         } else {
804                                 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
805                         }
806                         $sth->execute($default);
807                         print "  Alter $field in $table\n";
808                 }
809         }
810 }
811
812 # Get list of columns from borrowers table
813 my %itemtypes;
814 my %nullenabled;
815 $sth = $dbh->prepare("show columns from borrowers");
816 $sth->execute;
817 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
818 {
819     $itemtypes{$column} = $type;
820     $nullenabled{$column} = $null;
821 }
822
823 unless ( $itemtypes{'cardnumber'} eq 'varchar(20)' ) {
824     $itemtypes{'cardnumber'} =~ /varchar\((\d+)\)/;
825     my $oldlength = $1;
826     if ( $oldlength < 16 ) {
827         print "Setting maximum cardnumber length to 16 (was $oldlength) and marking unique.\n";
828         my $sti =
829           $dbh->prepare(
830             "alter table borrowers change cardnumber cardnumber varchar(16)");
831         $sti->execute;
832         $sti->finish;
833         $sti =
834           $dbh->prepare(
835             "alter table borrowers drop index cardnumber");
836         $sti->execute;
837         $sti->finish;
838         $sti =
839           $dbh->prepare(
840             "alter table borrowers add unique(cardnumber)");
841         $sti->execute;
842         $sti->finish;
843     }
844 }
845 #
846 # Get list of columns from items table
847 $sth = $dbh->prepare("show columns from items");
848 $sth->execute;
849 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
850 {
851     $itemtypes{$column} = $type;
852     $nullenabled{$column} = $null;
853 }
854
855 unless ( $itemtypes{'barcode'} eq 'varchar(20)' ) {
856     $itemtypes{'barcode'} =~ /varchar\((\d+)\)/;
857     my $oldlength = $1;
858     if ( $oldlength < 20 ) {
859         print "Setting maximum barcode length to 20 (was $oldlength).\n";
860         my $sti =
861           $dbh->prepare(
862             "alter table items change barcode barcode varchar(20)");
863         $sti->execute;
864     }
865 }
866 #
867 # dropping unique barcode index & setting barcode to null allowed.
868 #
869 $sth = $dbh->prepare("show index from items");
870 $sth->execute;
871 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
872 {
873         if ($key_name eq 'barcode' && $non_unique eq 0) {
874                 print "dropping BARCODE index to enable empty barcodes\n";
875                 $dbh->do("ALTER TABLE `items` DROP INDEX `barcode`");
876         }
877 }
878 $dbh->do("ALTER TABLE `items` CHANGE `barcode` `barcode` VARCHAR( 20 )") unless ($nullenabled{barcode} eq 'YES');
879
880 #
881 # creating fulltext index in bibliothesaurus if needed
882 #
883 $sth = $dbh->prepare("show index from bibliothesaurus");
884 $sth->execute;
885 my $exists=0;
886 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
887 {
888         if ($key_name eq 'category_2') {
889                 $exists=1;
890         }
891 }
892 print "Creating fulltext index on bibliothesaurus\n" unless $exists;
893 $dbh->do('create fulltext index category_2 on bibliothesaurus (category,freelib)') unless $exists;
894
895 #
896 # creating  index in z3950results if needed
897 #
898 $sth = $dbh->prepare("show index from z3950results");
899 $sth->execute;
900 my $exists=0;
901 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
902 {
903         if ($key_name eq 'query_server') {
904                 $exists=1;
905         }
906 }
907 print "Creating  index on z3950results\n" unless $exists;
908 $dbh->do('create unique index query_server on z3950results (queryid,server)') unless $exists;
909
910 # changing z3950daemon field to NULL in marc_breeding
911 $dbh->do("ALTER TABLE `marc_breeding` CHANGE `z3950random` `z3950random` VARCHAR( 40 )");
912
913 # making borrowernumber an auto_increment field
914 $dbh->do("ALTER TABLE `borrowers` CHANGE `borrowernumber` `borrowernumber` INTEGER auto_increment");
915
916 # extending the timestamp in branchtransfers...
917 my %branchtransfers;
918
919 $sth = $dbh->prepare("show columns from branchtransfers");
920 $sth->execute;
921 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
922 {
923     $branchtransfers{$column} = $type;
924 }
925
926 unless ( $branchtransfers{'datesent'} eq 'datetime' ) {
927     print "Setting type of datesent in branchtransfers to datetime.\n";
928     my $sti =
929       $dbh->prepare(
930         "alter table branchtransfers change datesent datesent datetime");
931     $sti->execute;
932 }
933
934 unless ( $branchtransfers{'datearrived'} eq 'datetime' ) {
935     print "Setting type of datearrived in branchtransfers to datetime.\n";
936     my $sti =
937       $dbh->prepare(
938         "alter table branchtransfers change datearrived datearrived datetime");
939     $sti->execute;
940 }
941
942 # changing the branchcategories table around...
943 my %branchcategories;
944
945 $sth = $dbh->prepare("show columns from branchcategories");
946 $sth->execute;
947 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
948 {
949     $branchcategories{$column} = $type;
950 }
951
952 unless ( $branchcategories{'categorycode'} eq 'varchar(4)' ) {
953     print
954 "Setting type of categorycode in branchcategories to varchar(4),\n and making the primary key.\n";
955     my $sti =
956       $dbh->prepare(
957 "alter table branchcategories change categorycode categorycode varchar(4) not null"
958     );
959     $sti->execute;
960     $sti =
961       $dbh->prepare(
962         "alter table branchcategories add primary key (categorycode)");
963     $sti->execute;
964 }
965
966 unless ( $branchcategories{'categoryname'} eq 'text' ) {
967     print "Changing branchcode in branchcategories to categoryname text.\n";
968     my $sth =
969       $dbh->prepare(
970         "alter table branchcategories change branchcode categoryname text");
971     $sth->execute;
972 }
973
974 unless ( $branchcategories{'codedescription'} eq 'text' ) {
975     print
976 "Replacing branchholding in branchcategories with codedescription text.\n";
977     my $sth =
978       $dbh->prepare(
979         "alter table branchcategories change branchholding codedescription text"
980     );
981     $sth->execute;
982 }
983
984 # changing the items table around...
985 my %items;
986
987 $sth = $dbh->prepare("show columns from items");
988 $sth->execute;
989 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
990 {
991     $items{$column} = $type;
992 }
993
994 if ($items{'bulk'} eq "varchar(30)") {
995     print "  Setting callnumber in items table\n";
996     my $sti =
997       $dbh->prepare("ALTER TABLE `items` CHANGE `bulk` `itemcallnumber` VARCHAR( 30 ) DEFAULT NULL");
998     $sti->execute;
999     $sti = $dbh->prepare("update marc_subfield_structure set kohafield=\"items.itemcallnumber\" where kohafield=\"items.bulk\"");
1000     $sti->execute;
1001 }
1002
1003 #
1004 # creating  index in issuingrules if needed
1005 #
1006 $sth = $dbh->prepare("show index from issuingrules");
1007 $sth->execute;
1008 my $exists=0;
1009 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1010 {
1011         if ($key_name eq 'PRIMARY') {
1012                 $exists=1;
1013         }
1014 }
1015 print "Creating  index on z3950results\n" unless $exists;
1016 $dbh->do('ALTER TABLE issuingrules ADD PRIMARY KEY ( branchcode, categorycode, itemtype )') unless $exists;
1017
1018
1019 # Populate tables with required data
1020
1021 foreach my $table ( keys %tabledata ) {
1022     print "Checking for data required in table $table...\n";
1023     my $tablerows = $tabledata{$table};
1024     foreach my $row (@$tablerows) {
1025         my $uniquefieldrequired = $row->{uniquefieldrequired};
1026         my $uniquevalue         = $row->{$uniquefieldrequired};
1027         my $forceupdate         = $row->{forceupdate};
1028         my $sth                 =
1029           $dbh->prepare(
1030 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1031         );
1032         $sth->execute($uniquevalue);
1033         if ($sth->rows) {
1034             foreach my $field (keys %$forceupdate) {
1035                 if ($forceupdate->{$field}) {
1036                     my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1037                     $sth->execute($row->{$field}, $uniquevalue);
1038                 }
1039             }
1040         } else {
1041             print "Adding row to $table: ";
1042             my @values;
1043             my $fieldlist;
1044             my $placeholders;
1045             foreach my $field ( keys %$row ) {
1046                 next if $field eq 'uniquefieldrequired';
1047                 next if $field eq 'forceupdate';
1048                 my $value = $row->{$field};
1049                 push @values, $value;
1050                 print "  $field => $value";
1051                 $fieldlist .= "$field,";
1052                 $placeholders .= "?,";
1053             }
1054             print "\n";
1055             $fieldlist    =~ s/,$//;
1056             $placeholders =~ s/,$//;
1057             my $sth =
1058               $dbh->prepare(
1059                 "insert into $table ($fieldlist) values ($placeholders)");
1060             $sth->execute(@values);
1061         }
1062     }
1063 }
1064
1065 $sth->finish;
1066
1067 exit;
1068
1069 # $Log$
1070 # Revision 1.77  2004/05/06 14:56:51  tipaul
1071 # adding table issuingrules (previously called categoryitem
1072 #
1073 # Revision 1.76  2004/05/03 09:32:25  tipaul
1074 # adding printcirculationsplit parameter (already existed, but was not in systempref by defaul)
1075 #
1076 # Revision 1.75  2004/04/14 19:49:00  tipaul
1077 # seealso field set to 255 chars
1078 #
1079 # Revision 1.74  2004/03/11 16:10:16  tipaul
1080 # *** empty log message ***
1081 #
1082 # Revision 1.73  2004/03/06 20:26:13  tipaul
1083 # adding seealso feature in MARC searches
1084 #