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