bugfixes for biblio deletion
[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 );
252
253 my %dropable_table = (
254     classification => 'classification',
255     multipart      => 'multipart',
256     multivolume    => 'multivolume',
257     newitems       => 'newitems',
258     procedures     => 'procedures',
259     publisher      => 'publisher',
260     searchstats    => 'searchstats',
261     serialissues   => 'serialissues',
262 );
263
264 # the other hash contains other actions that can't be done elsewhere. they are done
265 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
266
267 # The tabledata hash contains data that should be in the tables.
268 # The uniquefieldrequired hash entry is used to determine which (if any) fields
269 # must not exist in the table for this row to be inserted.  If the
270 # uniquefieldrequired entry is already in the table, the existing data is not
271 # modified, unless the forceupdate hash entry is also set.  Fields in the
272 # anonymous "forceupdate" hash will be forced to be updated to the default
273 # values given in the %tabledata hash.
274
275 my %tabledata = (
276     userflags => [
277         {
278             uniquefieldrequired => 'bit',
279             bit                 => 0,
280             flag                => 'superlibrarian',
281             flagdesc            => 'Access to all librarian functions',
282             defaulton           => 0
283         },
284         {
285             uniquefieldrequired => 'bit',
286             bit                 => 1,
287             flag                => 'circulate',
288             flagdesc            => 'Circulate books',
289             defaulton           => 0
290         },
291         {
292             uniquefieldrequired => 'bit',
293             bit                 => 2,
294             flag                => 'catalogue',
295             flagdesc            => 'View Catalogue (Librarian Interface)',
296             defaulton           => 0
297         },
298         {
299             uniquefieldrequired => 'bit',
300             bit                 => 3,
301             flag                => 'parameters',
302             flagdesc            => 'Set Koha system paramters',
303             defaulton           => 0
304         },
305         {
306             uniquefieldrequired => 'bit',
307             bit                 => 4,
308             flag                => 'borrowers',
309             flagdesc            => 'Add or modify borrowers',
310             defaulton           => 0
311         },
312         {
313             uniquefieldrequired => 'bit',
314             bit                 => 5,
315             flag                => 'permissions',
316             flagdesc            => 'Set user permissions',
317             defaulton           => 0
318         },
319         {
320             uniquefieldrequired => 'bit',
321             bit                 => 6,
322             flag                => 'reserveforothers',
323             flagdesc            => 'Reserve books for patrons',
324             defaulton           => 0
325         },
326         {
327             uniquefieldrequired => 'bit',
328             bit                 => 7,
329             flag                => 'borrow',
330             flagdesc            => 'Borrow books',
331             defaulton           => 1
332         },
333         {
334             uniquefieldrequired => 'bit',
335             bit                 => 8,
336             flag                => 'reserveforself',
337             flagdesc            => 'Reserve books for self',
338             defaulton           => 0
339         },
340         {
341             uniquefieldrequired => 'bit',
342             bit                 => 9,
343             flag                => 'editcatalogue',
344             flagdesc  => 'Edit Catalogue (Modify bibliographic/holdings data)',
345             defaulton => 0
346         },
347         {
348             uniquefieldrequired => 'bit',
349             bit                 => 10,
350             flag                => 'updatecharges',
351             flagdesc            => 'Update borrower charges',
352             defaulton           => 0
353         },
354     ],
355     systempreferences => [
356         {
357             uniquefieldrequired => 'variable',
358             forceupdate         => { 'explanation' => 1,
359                                      'type' => 1 },
360             variable            => 'autoMemberNum',
361             value               => '1',
362             explanation         => 'Member number is auto-calculated',
363             type                => 'YesNo'
364
365         },
366         {
367             uniquefieldrequired => 'variable',
368             forceupdate         => { 'explanation' => 1,
369                                      'type' => 1,
370                                      'options' => 1 },
371             variable            => 'acquisitions',
372             value               => 'simple',
373             explanation         =>
374 'Normal, budget-based acquisitions, or Simple bibliographic-data acquisitions',
375             type                => 'Choice',
376             options             => 'simple|normal'
377         },
378         {
379             uniquefieldrequired => 'variable',
380             forceupdate         => { 'explanation' => 1,
381                                      'type' => 1,
382                                      'options' => 1 },
383             variable            => 'dateformat',
384             value               => 'metric',
385             explanation         =>
386             'date format (US mm/dd/yyyy, metric dd/mm/yyy, ISO yyyy/mm/dd)',
387             type                => 'Choice',
388             options             => 'metric|us|iso'
389         },
390         {
391             uniquefieldrequired => 'variable',
392             variable            => 'template',
393             forceupdate         => { 'explanation' => 1,
394                                      'type' => 1 },
395             value               => 'default',
396             explanation         => 'Preference order for intranet interface templates',
397             type                => 'Themes'
398         },
399         {
400             uniquefieldrequired => 'variable',
401             variable            => 'autoBarcode',
402             forceupdate         => { 'explanation' => 1,
403                                      'type' => 1 },
404             value               => 'yes',
405             explanation         => 'Barcode is auto-calculated',
406             type                => 'YesNo'
407         },
408         {
409             uniquefieldrequired => 'variable',
410             variable            => 'insecure',
411             forceupdate         => { 'explanation' => 1,
412                                      'type' => 1 },
413             value               => 'no',
414             explanation         =>
415 'If YES, no auth at all is needed. Be careful if you set this to yes!',
416             type                => 'YesNo'
417         },
418         {
419             uniquefieldrequired => 'variable',
420             variable            => 'authoritysep',
421             forceupdate         => { 'explanation' => 1,
422                                      'type' => 1,
423                                      'options' => 1 },
424             value               => '--',
425             explanation         =>
426             'the separator used in authority/thesaurus. Usually --',
427             type                => 'free',
428             options             => '10'
429         },
430         {
431             uniquefieldrequired => 'variable',
432             variable            => 'opaclanguages',
433             forceupdate         => { 'explanation' => 1,
434                                      'type' => 1 },
435             value               => 'en',
436             explanation         => 'Set the preferred order for translations.  The top language will be tried first.',
437             type                => 'Languages'
438         },
439         {
440             uniquefieldrequired => 'variable',
441             variable            => 'opacthemes',
442             forceupdate         => { 'explanation' => 1,
443                                      'type' => 1 },
444             value               => 'default',
445             explanation         => 'Set the preferred order for themes.  The top theme will be tried first.',
446             type                => 'Themes'
447         },
448         {
449             uniquefieldrequired => 'variable',
450             variable            => 'timeout',
451             forceupdate         => { 'explanation' => 1,
452                                      'type' => 1 },
453             value               => '1200',
454             explanation         => 'Inactivity timeout for cookies authentication (in seconds)',
455             type                => 'Integer'
456         },
457         {
458             uniquefieldrequired => 'variable',
459             variable            => 'marc',
460             forceupdate         => { 'explanation' => 1,
461                                      'type' => 1 },
462             value               => 'yes',
463             explanation         => 'Turn on MARC support',
464             type                => 'YesNo'
465         },
466         {
467             uniquefieldrequired => 'variable',
468             variable            => 'marcflavour',
469             forceupdate         => { 'explanation' => 1,
470                                      'type' => 1,
471                                      'options' => 1},
472             value               => 'MARC21',
473             explanation         =>
474             'your MARC flavor (MARC21 or UNIMARC) used for character encoding',
475             type                => 'Choice',
476             options             => 'MARC21|UNIMARC'
477         },
478         {
479             uniquefieldrequired => 'variable',
480             variable            => 'checkdigit',
481             value               => 'none',
482             forceupdate         => { 'explanation' => 1,
483                                      'type' => 1,
484                                      'options' => 1},
485             explanation         => 'Validity checks on membership number: none or "Katipo" style checks',
486             type                => 'Choice',
487             options             => 'none|katipo'
488         },
489         {
490             uniquefieldrequired => 'variable',
491             variable            => 'maxoutstanding',
492             forceupdate         => { 'explanation' => 1,
493                                      'type' => 1 },
494             value               => '5',
495             explanation         =>
496             'maximum amount withstanding to be able make reserves ',
497             type                => 'Integer'
498         },
499         {
500             uniquefieldrequired => 'variable',
501             variable            => 'maxreserves',
502             forceupdate         => { 'explanation' => 1,
503                                      'type' => 1 },
504             value               => '5',
505             explanation         =>
506             'maximum number of reserves a member can make',
507             type                => 'Integer'
508
509         },
510         {
511             uniquefieldrequired => 'variable',
512             variable            => 'noissuescharge',
513             forceupdate         => { 'explanation' => 1,
514                                      'type' => 1 },
515             value               => '5',
516             explanation         =>
517             'maximum amount withstanding to be able to check out an item',
518             type                => 'Integer'
519
520         },
521         {
522             uniquefieldrequired => 'variable',
523             variable            => 'KohaAdminEmailAddress',
524             forceupdate         => { 'explanation' => 1,
525                                      'type' => 1 },
526             value               => 'your.mail@here',
527             explanation => 'the email address where borrowers modifs are sent',
528             type                => 'free'
529         },
530         {
531             uniquefieldrequired => 'variable',
532             variable            => 'gist',
533             forceupdate         => { 'explanation' => 1,
534                                      'type' => 1 },
535             value               => '0.125',
536             explanation => 'the gist rate. NOT in %, but in numeric form (0.12 for 12%)',
537             type                => 'free'
538         },
539     ],
540
541 );
542
543 my %fielddefinitions = (
544     printers => [
545         {
546             field   => 'printername',
547             type    => 'char(40)',
548             null    => '',
549             key     => 'PRI',
550             default => ''
551         },
552     ],
553     aqbookfund => [
554         {
555             field   => 'bookfundid',
556             type    => 'char(5)',
557             null    => '',
558             key     => 'PRI',
559             default => ''
560         },
561     ],
562     aqbudget => [
563         {
564             field   => 'aqbudgetid',
565             type    => 'tinyint(4)',
566             null    => '',
567             key     => 'PRI',
568                   default =>'',
569             extra => 'auto_increment'
570         },
571     ],
572     z3950servers => [
573         {
574             field   => 'id',
575             type    => 'int',
576             null    => '',
577             key     => 'PRI',
578             default => '',
579             extra   => 'auto_increment'
580         },
581     ],
582         marc_breeding => [
583         {
584             field   => 'z3950random',
585             type    => 'varchar(40)',
586             null    => 'NULL',
587             key     => '',
588             default => '',
589             extra   => ''
590         },
591         {
592             field   => 'encoding',
593             type    => 'varchar(40)',
594             null    => '',
595             key     => '',
596             default => '',
597             extra   => ''
598         },
599     ],
600 );
601
602 #-------------------
603 # Initialize
604
605 # Start checking
606
607 # Get version of MySQL database engine.
608 my $mysqlversion = `mysqld --version`;
609 $mysqlversion =~ /Ver (\S*) /;
610 $mysqlversion = $1;
611 if ( $mysqlversion ge '3.23' ) {
612     print "Could convert to MyISAM database tables...\n";
613 }
614
615 #---------------------------------
616 # Tables
617
618 # Collect all tables into a list
619 $sth = $dbh->prepare("show tables");
620 $sth->execute;
621 while ( my ($table) = $sth->fetchrow ) {
622     $existingtables{$table} = 1;
623 }
624
625
626 # Now add any missing tables
627 foreach $table ( keys %requiretables ) {
628     unless ( $existingtables{$table} ) {
629         print "Adding $table table...\n";
630         my $sth = $dbh->prepare("create table $table $requiretables{$table}");
631         $sth->execute;
632         if ( $sth->err ) {
633             print "Error : $sth->errstr \n";
634             $sth->finish;
635         }    # if error
636     }    # unless exists
637 }    # foreach
638
639 # now drop useless tables
640 foreach $table ( keys %dropable_table ) {
641         if ( $existingtables{$table} ) {
642                 print "Dropping unused table $table\n" if $debug;
643                 $dbh->do("drop table $table");
644                 if ( $dbh->err ) {
645                         print "Error : $dbh->errstr \n";
646                 }
647         }
648 }
649 unless ( $existingtables{'z3950servers'} ) {
650         #MJR: added syntax entries to close bug 624
651     print "Adding z3950servers table...\n";
652     my $sti = $dbh->prepare( "create table z3950servers (
653                                                                                 host char(255),
654                                                                                 port int,
655                                                                                 db char(255),
656                                                                                 userid char(255),
657                                                                                 password char(255),
658                                                                                 name text,
659                                                                                 id int,
660                                                                                 checked smallint,
661                                                                                 rank int,
662                                                                                 syntax char(80))"
663     );
664     $sti->execute;
665     $sti = $dbh->prepare( "insert into z3950servers
666                                                                 values ('z3950.loc.gov',
667                                                                 7090,
668                                                                 'voyager',
669                                                                 '', '',
670                                                                 'Library of Congress',
671                                                                 1, 1, 1, 'USMARC')"
672     );
673     $sti->execute;
674 }
675
676 #---------------------------------
677 # Columns
678
679 foreach $table ( keys %requirefields ) {
680     print "Check table $table\n" if $debug;
681     $sth = $dbh->prepare("show columns from $table");
682     $sth->execute();
683     undef %types;
684     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
685     {
686         $types{$column} = $type;
687     }    # while
688     foreach $column ( keys %{ $requirefields{$table} } ) {
689         print "  Check column $column  [$types{$column}]\n" if $debug;
690         if ( !$types{$column} ) {
691
692             # column doesn't exist
693             print "Adding $column field to $table table...\n";
694             $query = "alter table $table
695                         add column $column " . $requirefields{$table}->{$column};
696             print "Execute: $query\n" if $debug;
697             my $sti = $dbh->prepare($query);
698             $sti->execute;
699             if ( $sti->err ) {
700                 print "**Error : $sti->errstr \n";
701                 $sti->finish;
702             }    # if error
703         }    # if column
704     }    # foreach column
705 }    # foreach table
706
707 foreach $table ( keys %fielddefinitions ) {
708         print "Check table $table\n" if $debug;
709         $sth = $dbh->prepare("show columns from $table");
710         $sth->execute();
711         my $definitions;
712         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
713         {
714                 $definitions->{$column}->{type}    = $type;
715                 $definitions->{$column}->{null}    = $null;
716                 $definitions->{$column}->{key}     = $key;
717                 $definitions->{$column}->{default} = $default;
718                 $definitions->{$column}->{extra}   = $extra;
719         }    # while
720         my $fieldrow = $fielddefinitions{$table};
721         foreach my $row (@$fieldrow) {
722                 my $field   = $row->{field};
723                 my $type    = $row->{type};
724                 my $null    = $row->{null};
725                 my $key     = $row->{key};
726                 my $default = $row->{default};
727                 $default="''" unless $default;
728                 my $extra   = $row->{extra};
729                 my $def     = $definitions->{$field};
730                 unless ( $type eq $def->{type}
731                         && $null eq $def->{null}
732                         && $key eq $def->{key}
733                         && $default eq $def->{default}
734                         && $extra eq $def->{extra} )
735                 {
736
737                         if ( $null eq '' ) {
738                                 $null = 'NOT NULL';
739                         }
740                         if ( $key eq 'PRI' ) {
741                                 $key = 'PRIMARY KEY';
742                         }
743                         unless ( $extra eq 'auto_increment' ) {
744                                 $extra = '';
745                         }
746                         # if it's a new column use "add", if it's an old one, use "change".
747                         my $action;
748                         if ($definitions->{$field}->{type}) {
749                                 $action="change $field"
750                         } else {
751                                 $action="add";
752                         }
753 # if it's a primary key, drop the previous pk, before altering the table
754                         my $sth;
755                         if ($key ne 'PRIMARY KEY') {
756                                 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
757                         } else {
758                                 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
759                         }
760                         $sth->execute($default);
761                         print "  Alter $field in $table\n";
762                 }
763         }
764 }
765
766 # Get list of columns from borrowers table
767 my %itemtypes;
768 my %nullenabled;
769 $sth = $dbh->prepare("show columns from borrowers");
770 $sth->execute;
771 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
772 {
773     $itemtypes{$column} = $type;
774     $nullenabled{$column} = $null;
775 }
776
777 unless ( $itemtypes{'cardnumber'} eq 'varchar(20)' ) {
778     $itemtypes{'cardnumber'} =~ /varchar\((\d+)\)/;
779     my $oldlength = $1;
780     if ( $oldlength < 16 ) {
781         print "Setting maximum cardnumber length to 16 (was $oldlength) and marking unique.\n";
782         my $sti =
783           $dbh->prepare(
784             "alter table borrowers change cardnumber cardnumber varchar(16)");
785         $sti->execute;
786         $sti->finish;
787         $sti =
788           $dbh->prepare(
789             "alter table borrowers drop index cardnumber");
790         $sti->execute;
791         $sti->finish;
792         $sti =
793           $dbh->prepare(
794             "alter table borrowers add unique(cardnumber)");
795         $sti->execute;
796         $sti->finish;
797     }
798 }
799 #
800 # Get list of columns from items table
801 $sth = $dbh->prepare("show columns from items");
802 $sth->execute;
803 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
804 {
805     $itemtypes{$column} = $type;
806     $nullenabled{$column} = $null;
807 }
808
809 unless ( $itemtypes{'barcode'} eq 'varchar(20)' ) {
810     $itemtypes{'barcode'} =~ /varchar\((\d+)\)/;
811     my $oldlength = $1;
812     if ( $oldlength < 20 ) {
813         print "Setting maximum barcode length to 20 (was $oldlength).\n";
814         my $sti =
815           $dbh->prepare(
816             "alter table items change barcode barcode varchar(20)");
817         $sti->execute;
818     }
819 }
820 #
821 # dropping unique barcode index & setting barcode to null allowed.
822 #
823 $sth = $dbh->prepare("show index from items");
824 $sth->execute;
825 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
826 {
827         if ($key_name eq 'barcode' && $non_unique eq 0) {
828                 print "dropping BARCODE index to enable empty barcodes\n";
829                 $dbh->do("ALTER TABLE `items` DROP INDEX `barcode`");
830         }
831 }
832 $dbh->do("ALTER TABLE `items` CHANGE `barcode` `barcode` VARCHAR( 20 )") unless ($nullenabled{barcode} eq 'YES');
833
834 #
835 # creating fulltext index in bibliothesaurus if needed
836 #
837 $sth = $dbh->prepare("show index from bibliothesaurus");
838 $sth->execute;
839 my $exists=0;
840 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
841 {
842         if ($key_name eq 'category_2') {
843                 $exists=1;
844         }
845 }
846 print "Creating fulltext index on bibliothesaurus\n" unless $exists;
847 $dbh->do('create fulltext index category_2 on bibliothesaurus (category,freelib)') unless $exists;
848
849 # changing z3950daemon field to NULL in marc_breeding
850 $dbh->do("ALTER TABLE `marc_breeding` CHANGE `z3950random` `z3950random` VARCHAR( 40 )");
851
852 # making borrowernumber an auto_increment field
853 $dbh->do("ALTER TABLE `borrowers` CHANGE `borrowernumber` `borrowernumber` INTEGER auto_increment");
854
855 # extending the timestamp in branchtransfers...
856 my %branchtransfers;
857
858 $sth = $dbh->prepare("show columns from branchtransfers");
859 $sth->execute;
860 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
861 {
862     $branchtransfers{$column} = $type;
863 }
864
865 unless ( $branchtransfers{'datesent'} eq 'datetime' ) {
866     print "Setting type of datesent in branchtransfers to datetime.\n";
867     my $sti =
868       $dbh->prepare(
869         "alter table branchtransfers change datesent datesent datetime");
870     $sti->execute;
871 }
872
873 unless ( $branchtransfers{'datearrived'} eq 'datetime' ) {
874     print "Setting type of datearrived in branchtransfers to datetime.\n";
875     my $sti =
876       $dbh->prepare(
877         "alter table branchtransfers change datearrived datearrived datetime");
878     $sti->execute;
879 }
880
881 # changing the branchcategories table around...
882 my %branchcategories;
883
884 $sth = $dbh->prepare("show columns from branchcategories");
885 $sth->execute;
886 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
887 {
888     $branchcategories{$column} = $type;
889 }
890
891 unless ( $branchcategories{'categorycode'} eq 'varchar(4)' ) {
892     print
893 "Setting type of categorycode in branchcategories to varchar(4),\n and making the primary key.\n";
894     my $sti =
895       $dbh->prepare(
896 "alter table branchcategories change categorycode categorycode varchar(4) not null"
897     );
898     $sti->execute;
899     $sti =
900       $dbh->prepare(
901         "alter table branchcategories add primary key (categorycode)");
902     $sti->execute;
903 }
904
905 unless ( $branchcategories{'categoryname'} eq 'text' ) {
906     print "Changing branchcode in branchcategories to categoryname text.\n";
907     my $sth =
908       $dbh->prepare(
909         "alter table branchcategories change branchcode categoryname text");
910     $sth->execute;
911 }
912
913 unless ( $branchcategories{'codedescription'} eq 'text' ) {
914     print
915 "Replacing branchholding in branchcategories with codedescription text.\n";
916     my $sth =
917       $dbh->prepare(
918         "alter table branchcategories change branchholding codedescription text"
919     );
920     $sth->execute;
921 }
922
923 # Populate tables with required data
924
925 foreach my $table ( keys %tabledata ) {
926     print "Checking for data required in table $table...\n";
927     my $tablerows = $tabledata{$table};
928     foreach my $row (@$tablerows) {
929         my $uniquefieldrequired = $row->{uniquefieldrequired};
930         my $uniquevalue         = $row->{$uniquefieldrequired};
931         my $forceupdate         = $row->{forceupdate};
932         my $sth                 =
933           $dbh->prepare(
934 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
935         );
936         $sth->execute($uniquevalue);
937         if ($sth->rows) {
938             foreach my $field (keys %$forceupdate) {
939                 if ($forceupdate->{$field}) {
940                     my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
941                     $sth->execute($row->{$field}, $uniquevalue);
942                 }
943             }
944         } else {
945             print "Adding row to $table: ";
946             my @values;
947             my $fieldlist;
948             my $placeholders;
949             foreach my $field ( keys %$row ) {
950                 next if $field eq 'uniquefieldrequired';
951                 next if $field eq 'forceupdate';
952                 my $value = $row->{$field};
953                 push @values, $value;
954                 print "  $field => $value";
955                 $fieldlist .= "$field,";
956                 $placeholders .= "?,";
957             }
958             print "\n";
959             $fieldlist    =~ s/,$//;
960             $placeholders =~ s/,$//;
961             my $sth =
962               $dbh->prepare(
963                 "insert into $table ($fieldlist) values ($placeholders)");
964             $sth->execute(@values);
965         }
966     }
967 }
968
969 $sth->finish;
970
971 exit;
972
973 # $Log$
974 # Revision 1.68  2003/12/03 17:47:14  tipaul
975 # bugfixes for biblio deletion
976 #
977 # Revision 1.67  2003/11/28 10:08:33  tipaul
978 # * removing too verbose messages.
979 # * creating a fulltext index on bibliothesaurus
980 #
981 # Revision 1.66  2003/11/12 16:14:42  slef
982 # lengthen cardnumber to 16 and make it unique
983 #
984 # Revision 1.65  2003/11/06 15:07:11  tipaul
985 # adding marc fields in deletedbiblio & deleteditems
986 #
987 # Revision 1.64  2003/10/23 20:33:53  rangi
988 # Making the borrowenumber an auto_increment field
989 #
990 # Revision 1.63  2003/10/20 16:13:01  slef
991 # Omitted annotation added. Closes: 624
992 #
993 # Revision 1.62  2003/10/20 16:10:19  slef
994 # Adding USMARC to LOC z3950 entry
995 #
996 # Revision 1.61  2003/10/01 15:03:45  tipaul
997 # oups... typo fix in z3950random field definition
998 #
999 # Revision 1.59  2003/09/30 16:22:05  tipaul
1000 # adding barcode NOT mandatory feature. Just run updatedatabase to get it.
1001 # Note it's impossible to issue an item without barcode, as issue/returns is based on barcode...
1002 #
1003 # Revision 1.58  2003/07/16 04:08:29  acli
1004 # Minor spelling correction
1005 #
1006 # Revision 1.57  2003/07/11 11:50:29  tipaul
1007 # fixing a bug that occured when adding a field into a table.
1008 #
1009 # Revision 1.56  2003/07/07 15:37:20  tipaul
1010 # *** empty log message ***
1011 #
1012 # Revision 1.53  2003/07/07 14:11:16  tipaul
1013 # fixing bug #526 : gst rate is now calculated through systempref gist entry.
1014 # Before this fix :
1015 # * was harcoded to 12,5%
1016 # * some bugs in template parameters prevented the javascript to work.
1017 # * some bugs prevented some calculations to be done properly.
1018 #
1019 # Revision 1.52  2003/06/23 15:54:32  tipaul
1020 # *** empty log message ***
1021 #
1022 # Revision 1.51  2003/06/23 11:27:29  tipaul
1023 # *** empty log message ***
1024 #
1025 # Revision 1.50  2003/06/11 21:28:22  tonnesen
1026 # Added modifications required to the systempreferences table by the new
1027 # systempreferences.pl script.  The systempreferences.pl script will not work
1028 # properly until this table is updated.
1029 #
1030 # Revision 1.49  2003/05/26 10:41:53  tipaul
1031 # bugfix : borrowers modifs overwritten by stupid hash entry existing twice.
1032 #
1033 # Revision 1.48  2003/05/20 19:50:45  slef
1034 # Initial fix to bug 456: hardwired paths
1035 #
1036 # Revision 1.47  2003/05/15 12:23:33  tipaul
1037 # adding zipcode and homezipcode into borrowers table (bug #246
1038 #
1039 # Revision 1.46  2003/05/08 12:48:24  wolfpac444
1040 # Added "noissuescharge" parameter
1041 #
1042 # Revision 1.45  2003/05/08 12:26:16  wolfpac444
1043 # Bug fixes
1044 #
1045 # Revision 1.44  2003/05/03 05:39:57  rangi
1046 # Fixing bug 429
1047 # (Wording changes in the explanation fields in system preferences)
1048 #
1049 # Revision 1.43  2003/05/02 23:01:09  rangi
1050 # Adding the textmessaging column to the borrowers table.
1051 # insertdata.pl is expecting this to exist, and hence modifying/adding
1052 # borrowers was broken.
1053 #
1054 # Also ran they script thru perltidy
1055 #
1056 # Revision 1.42  2003/04/29 16:53:25  tipaul
1057 # really proud of this commit :-)
1058 # z3950 search and import seems to works fine.
1059 # Let me explain how :
1060 # * a "search z3950" button is added in the addbiblio template.
1061 # * when clicked, a popup appears and z3950/search.pl is called
1062 # * z3950/search.pl calls addz3950search in the DB
1063 # * the z3950 daemon retrieve the records and stores them in z3950results AND in marc_breeding table.
1064 # * as long as there as searches pending, the popup auto refresh every 2 seconds, and says how many searches are pending.
1065 # * when the user clicks on a z3950 result => the parent popup is called with the requested biblio, and auto-filled
1066 #
1067 # Note :
1068 # * character encoding support : (It's a nightmare...) In the z3950servers table, a "encoding" column has been added. You can put "UNIMARC" or "USMARC" in this column. Depending on this, the char_decode in C4::Biblio.pm replaces marc-char-encode by an iso 8859-1 encoding. Note that in the breeding import this value has been added too, for a better support.
1069 # * the marc_breeding and z3950* tables have been modified : they have an encoding column and the random z3950 number is stored too for convenience => it's the key I use to list only requested biblios in the popup.
1070 #
1071 # Revision 1.41  2003/04/29 08:09:44  tipaul
1072 # z3950 support is coming...
1073 # * adding a syntax column in z3950 table = this column will say wether the z3950 must be called with PerferedRecordsyntax => USMARC or PerferedRecordsyntax => UNIMARC. I tried some french UNIMARC z3950 servers, and some only send USMARC, some only UNIMARC, some can answer with both.
1074 # Note this is a 1st draft. More to follow (today ? I hope).
1075 #
1076 # Revision 1.40  2003/04/22 10:48:27  wolfpac444
1077 # Added "father" column to bibliothesaurus table
1078 #
1079 # Revision 1.39  2003/04/04 08:45:00  tipaul
1080 # last commits before 1.9.1
1081 #
1082 # Revision 1.38  2003/03/18 10:58:19  tipaul
1083 # adding checkdigit parameter that choose how to check the members cardnumber.
1084 # At the moment :
1085 # * none = no checking
1086 # * katipo = checked as before
1087 #
1088 # Revision 1.37  2003/01/30 01:47:48  acli
1089 # Corrected syntax error reported by Benedict
1090 #
1091 # Made the indentation somewhat easier to read; the messiness probably caused
1092 # the original syntax error.
1093 #
1094 # Revision 1.36  2003/01/28 15:13:30  tipaul
1095 # userflag table now created in upgrade script (bugfix #171)
1096 #
1097 # Revision 1.35  2003/01/27 03:12:49  acli
1098 # Reworded the description for "acquisitions" to make it fit on the screen
1099 #
1100 # Added "iso" to dateformat, since dateformat is not yet being used anyway
1101 #
1102 # Revision 1.34  2003/01/23 12:30:02  tipaul
1103 # introducint marcflavour in systempref file : used for character decoding
1104 #
1105 # Revision 1.33  2003/01/21 09:03:27  tipaul
1106 # bugfix (NOTE : this bugs makes installation of the 1.3.3 a little fuzzy. Please fix your DB if you installed 1.3.3)
1107 #
1108 # Revision 1.32  2003/01/16 10:29:45  tipaul
1109 # adding a MARC parameter in systempref ( which is ON or OFF)
1110 # the search will be a marc search if MARC=ON
1111 # and a standard (v1.2) search if MARC=OFF
1112 #
1113 # Revision 1.31  2003/01/06 13:32:43  tipaul
1114 # *** empty log message ***
1115 #
1116 # Revision 1.29  2003/01/06 11:14:11  tipaul
1117 # last bugfixes before 1.3.3 : systempref table correctly filled
1118 #
1119 # Revision 1.28  2002/12/10 13:27:47  tipaul
1120 # bugfixes (davide mails in koha-dev)
1121 #
1122 # Revision 1.27  2002/11/26 15:04:54  tipaul
1123 # road to 1.3.2. Updating db structure during installation
1124 #
1125 # Revision 1.26  2002/11/12 17:42:40  tonnesen
1126 # Merged some features over from rel-1-2, including primary key checking.
1127 #
1128 # Revision 1.25  2002/11/12 16:44:38  tipaul
1129 # road to 1.3.2 :
1130 # * many bugfixes
1131 # * adding value_builder : you can map a subfield in the marc_subfield_structure to a sub stored in "value_builder" directory. In this directory you can create screen used to build values with any method. In this commit is a 1st draft of the builder for 100$a unimarc french subfield, which is composed of 35 digits, with 12 differents values (only the 4th first are provided for instance)
1132 #
1133 # Revision 1.24  2002/10/30 14:00:23  arensb
1134 # (bug fix): Fixed typo.
1135 #
1136 # Revision 1.23  2002/10/25 10:55:46  tipaul
1137 # Road to 1.3.2
1138 # * bugfixes and improvements
1139 # * manage mandatory MARC subfields
1140 # * new table : authorised_values. this table contains categories and authorised values for the category. On MARC management, you can map a subfield to a authorised_values category. If you do this, the subfield can only be filled with a authorised_value of the selected category.
1141 # this submit contains everything needed :
1142 # * updatedatabase
1143 # * admin screens
1144 # * "links" management
1145 # * creation of a html-list if a subfield is mapped to an authorised value.
1146 #
1147 # Note this is different from authorities support, which will come soon.
1148 # The authorised_values is supposed to contains a "small" number of authorised values for a category (less than 50-100). If you enter more authorised values than this, it should be hard to find what you want in a BIG list...
1149 #
1150 # Revision 1.22  2002/10/15 10:08:19  tipaul
1151 # fixme corrected, re-indent and adding the marc_breeding table (see commit of marcimport.pl for more explanations about breeding)
1152 #
1153 # Revision 1.21  2002/10/14 11:48:59  tipaul
1154 # bugfix
1155 #
1156 # Revision 1.20  2002/10/10 04:49:41  arensb
1157 # Added some FIXME comments.
1158 #
1159 # Revision 1.19  2002/10/05 10:17:17  arensb
1160 # Merged with arensb-context branch: use C4::Context->dbh instead of
1161 # &C4Connect, and generally prefer C4::Context over C4::Database.
1162 #
1163 # Revision 1.18.2.2  2002/10/05 06:18:43  arensb
1164 # Added a whole mess of FIXME comments.
1165 #
1166 # Revision 1.18.2.1  2002/10/04 02:46:00  arensb
1167 # Use C4::Connect instead of C4::Database, C4::Connect->dbh instead
1168 # C4Connect.
1169 #
1170 # Revision 1.18  2002/09/24 13:50:55  tipaul
1171 # long WAS the road to 1.3.0...
1172 # coming VERY SOON NOW...
1173 # modifying installer and buildrelease to update the DB
1174 #
1175 # Revision 1.17  2002/09/24 12:57:35  tipaul
1176 # long WAS the road to 1.3.0...
1177 # coming VERY SOON NOW...
1178 # modifying installer and buildrelease to update the DB
1179 #
1180 # Revision 1.16  2002/07/31 02:34:27  finlayt
1181 #
1182 # added "notforloan" field to the itemtypes table.
1183 #
1184 # Revision 1.15  2002/07/20 22:30:06  rangi
1185 # Making sure fix makes it into the main branch as well
1186 # Fix for bug 69
1187 #
1188 # Revision 1.14  2002/07/08 16:20:26  tonnesen
1189 # Added sessionqueries table and password/userid fields to borrowers table
1190 #
1191 # Revision 1.13  2002/07/04 18:05:36  tonnesen
1192 # bug fix
1193 #
1194 # Revision 1.12  2002/07/04 16:41:06  tonnesen
1195 # Merged changes from rel-1-2.  Abstracted table structure changes by alan.
1196 #