DB modifs : merging tag & subfield in marc_word table
[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         auth_types => "(
212                                         authtypecode char(10) not NULL,
213                                         authtypetext char(255) not NULL,
214                                         auth_tag_to_report char(3) not NULL,
215                                         summary text not NULL,
216                                         PRIMARY KEY (authtypecode)
217                         )",
218         biblio_framework => "(
219                                         frameworkcode char(4) not NULL,
220                                         frameworktext char(255) not NULL,
221                                         PRIMARY KEY (frameworkcode)
222                         )",
223     auth_subfield_structure => "(
224                                         authtypecode char(10) NOT NULL default '',
225                                         tagfield char(3) NOT NULL default '',
226                                         tagsubfield char(1) NOT NULL default '',
227                                         liblibrarian char(255) NOT NULL default '',
228                                         libopac char(255) NOT NULL default '',
229                                         repeatable tinyint(4) NOT NULL default '0',
230                                         mandatory tinyint(4) NOT NULL default '0',
231                                         tab tinyint(1) default NULL,
232                                         authorised_value char(10) default NULL,
233                                         value_builder char(80) default NULL,
234                                         seealso char(255) default NULL,
235                                         PRIMARY KEY  (authtypecode,tagfield,tagsubfield),
236                                         KEY tab (authtypecode,tab)
237                                         )",
238     auth_tag_structure => "(
239                                         authtypecode char(10) NOT NULL default '',
240                                         tagfield char(3) NOT NULL default '',
241                                         liblibrarian char(255) NOT NULL default '',
242                                         libopac char(255) NOT NULL default '',
243                                         repeatable tinyint(4) NOT NULL default '0',
244                                         mandatory tinyint(4) NOT NULL default '0',
245                                         authorised_value char(10) default NULL,
246                                         PRIMARY KEY  (authtypecode,tagfield)
247                                         )",
248     auth_header => "(
249                                                 authid bigint(20) unsigned NOT NULL auto_increment,
250                                                 datecreated date NOT NULL default '0000-00-00',
251                                                 datemodified date default NULL,
252                                                 origincode char(20) default NULL,
253                                                 PRIMARY KEY  (authid),
254                                                 KEY origincode (origincode),
255                                                 ) ",
256     auth_subfield_table => "(
257                                                 subfieldid bigint(20) unsigned NOT NULL auto_increment,
258                                                 authid bigint(20) unsigned NOT NULL default '0',
259                                                 tag char(3) NOT NULL default '',
260                                                 tagorder tinyint(4) NOT NULL default '1',
261                                                 tag_indicator char(2) NOT NULL default '',
262                                                 subfieldcode char(1) NOT NULL default '',
263                                                 subfieldorder tinyint(4) NOT NULL default '1',
264                                                 subfieldvalue varchar(255) default NULL,
265                                                 PRIMARY KEY  (subfieldid),
266                                                 KEY authid (authid),
267                                                 KEY tag (tag),
268                                                 KEY subfieldcode (subfieldcode),
269                                                 KEY subfieldvalue (subfieldvalue)
270                                         )",
271     auth_word => "(
272                                 authid bigint(20) NOT NULL default '0',
273                                 tagsubfield char(4) NOT NULL default '',
274                                 tagorder tinyint(4) NOT NULL default '1',
275                                 subfieldorder tinyint(4) NOT NULL default '1',
276                                 word varchar(255) NOT NULL default '',
277                                 sndx_word varchar(255) NOT NULL default '',
278                                 KEY authid (authid),
279                                 KEY marc_search (tagsubfield,word),
280                                 KEY word (word),
281                                 KEY sndx_word (sndx_word)
282                         )",
283 );
284
285 my %requirefields = (
286     biblio        => { 'abstract' => 'text' },
287     deletedbiblio => { 'abstract' => 'text', 'marc' => 'blob' },
288     deleteditems => { 'marc' => 'blob', 'paidfor' => 'text' },
289     biblioitems   => {
290         'lccn' => 'char(25)',
291         'url'  => 'varchar(255)',
292         'marc' => 'text'
293     },
294     deletedbiblioitems => {
295         'lccn' => 'char(25)',
296         'url'  => 'varchar(255)',
297         'marc' => 'text'
298     },
299     branchtransfers => { 'datearrived'    => 'datetime' },
300     statistics      => { 'borrowernumber' => 'int(11)' },
301     aqbooksellers   => {
302         'invoicedisc' => 'float(6,4)',
303         'nocalc'      => 'int(11)'
304     },
305     borrowers => {
306         'userid'        => 'char(30)',
307         'password'      => 'char(30)',
308         'flags'         => 'int(11)',
309         'textmessaging' => 'varchar(30)',
310            'zipcode' => 'varchar(25)',
311                         'homezipcode' => 'varchar(25)',
312     },
313     aqorders => { 'budgetdate' => 'date' },
314     aqbudget => {'aqbudgetid' => 'tinyint(4) auto_increment primary key'},
315     items => {'paidfor' => 'text'},
316
317     #added so that reference items are not available for reserves...
318     itemtypes         => { 'notforloan'  => 'smallint(6)' },
319     systempreferences => { 'explanation' => 'char(80)',
320                            'type' => 'char(20)',
321                            'options' => 'text' },
322     z3950servers      => { 'syntax'      => 'char(80)' },
323         marc_tag_structure =>{
324                                                         'frameworkcode' => 'char(4) not NULL default \'\''},
325     marc_subfield_structure =>{'seealso'  => 'char(255)',
326                                                         'frameworkcode' => 'char(4) not NULL default \'\'',
327                                                         'hidden' => 'tinyint(1)',
328                                                         'isurl' => 'tinyint(1)',
329                                                         },
330     bookshelf => {'owner' => 'char(80)',
331                                         'category' => 'char(1)',
332                                 },
333     marc_biblio        => { 'frameworkcode' => 'char(4) not NULL default \'\'' },
334 );
335
336 my %dropable_table = (
337     classification => 'classification',
338     multipart      => 'multipart',
339     multivolume    => 'multivolume',
340     newitems       => 'newitems',
341     procedures     => 'procedures',
342     publisher      => 'publisher',
343     searchstats    => 'searchstats',
344     serialissues   => 'serialissues',
345 );
346
347 # the other hash contains other actions that can't be done elsewhere. they are done
348 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
349
350 # The tabledata hash contains data that should be in the tables.
351 # The uniquefieldrequired hash entry is used to determine which (if any) fields
352 # must not exist in the table for this row to be inserted.  If the
353 # uniquefieldrequired entry is already in the table, the existing data is not
354 # modified, unless the forceupdate hash entry is also set.  Fields in the
355 # anonymous "forceupdate" hash will be forced to be updated to the default
356 # values given in the %tabledata hash.
357
358 my %tabledata = (
359     userflags => [
360         {
361             uniquefieldrequired => 'bit',
362             bit                 => 0,
363             flag                => 'superlibrarian',
364             flagdesc            => 'Access to all librarian functions',
365             defaulton           => 0
366         },
367         {
368             uniquefieldrequired => 'bit',
369             bit                 => 1,
370             flag                => 'circulate',
371             flagdesc            => 'Circulate books',
372             defaulton           => 0
373         },
374         {
375             uniquefieldrequired => 'bit',
376             bit                 => 2,
377             flag                => 'catalogue',
378             flagdesc            => 'View Catalogue (Librarian Interface)',
379             defaulton           => 0
380         },
381         {
382             uniquefieldrequired => 'bit',
383             bit                 => 3,
384             flag                => 'parameters',
385             flagdesc            => 'Set Koha system paramters',
386             defaulton           => 0
387         },
388         {
389             uniquefieldrequired => 'bit',
390             bit                 => 4,
391             flag                => 'borrowers',
392             flagdesc            => 'Add or modify borrowers',
393             defaulton           => 0
394         },
395         {
396             uniquefieldrequired => 'bit',
397             bit                 => 5,
398             flag                => 'permissions',
399             flagdesc            => 'Set user permissions',
400             defaulton           => 0
401         },
402         {
403             uniquefieldrequired => 'bit',
404             bit                 => 6,
405             flag                => 'reserveforothers',
406             flagdesc            => 'Reserve books for patrons',
407             defaulton           => 0
408         },
409         {
410             uniquefieldrequired => 'bit',
411             bit                 => 7,
412             flag                => 'borrow',
413             flagdesc            => 'Borrow books',
414             defaulton           => 1
415         },
416         {
417             uniquefieldrequired => 'bit',
418             bit                 => 8,
419             flag                => 'reserveforself',
420             flagdesc            => 'Reserve books for self',
421             defaulton           => 0
422         },
423         {
424             uniquefieldrequired => 'bit',
425             bit                 => 9,
426             flag                => 'editcatalogue',
427             flagdesc  => 'Edit Catalogue (Modify bibliographic/holdings data)',
428             defaulton => 0
429         },
430         {
431             uniquefieldrequired => 'bit',
432             bit                 => 10,
433             flag                => 'updatecharges',
434             flagdesc            => 'Update borrower charges',
435             defaulton           => 0
436         },
437     ],
438     systempreferences => [
439         {
440             uniquefieldrequired => 'variable',
441             forceupdate         => { 'explanation' => 1,
442                                      'type' => 1 },
443             variable            => 'LibraryName',
444             value               => '<i><b>Koha<br/>Free Software ILS<br/><br/></b>Koha : a gift, a contribution<br/> in Maori</i>',
445             explanation         => 'Library name as shown on main opac page',
446             type                => ''
447
448         },
449         {
450             uniquefieldrequired => 'variable',
451             forceupdate         => { 'explanation' => 1,
452                                      'type' => 1 },
453             variable            => 'autoMemberNum',
454             value               => '1',
455             explanation         => 'Member number is auto-calculated',
456             type                => 'YesNo'
457
458         },
459         {
460             uniquefieldrequired => 'variable',
461             forceupdate         => { 'explanation' => 1,
462                                      'type' => 1,
463                                      'options' => 1 },
464             variable            => 'acquisitions',
465             value               => 'normal',
466             explanation         =>
467 'Normal, budget-based acquisitions, or Simple bibliographic-data acquisitions',
468             type                => 'Choice',
469             options             => 'simple|normal'
470         },
471         {
472             uniquefieldrequired => 'variable',
473             forceupdate         => { 'explanation' => 1,
474                                      'type' => 1,
475                                      'options' => 1 },
476             variable            => 'dateformat',
477             value               => 'metric',
478             explanation         =>
479             'date format (us mm/dd/yyyy, metric dd/mm/yyy, ISO yyyy/mm/dd)',
480             type                => 'Choice',
481             options             => 'metric|us|iso'
482         },
483         {
484             uniquefieldrequired => 'variable',
485             variable            => 'template',
486             forceupdate         => { 'explanation' => 1,
487                                      'type' => 1 },
488             value               => 'default',
489             explanation         => 'Preference order for intranet interface templates',
490             type                => 'Themes'
491         },
492         {
493             uniquefieldrequired => 'variable',
494             variable            => 'autoBarcode',
495             forceupdate         => { 'explanation' => 1,
496                                      'type' => 1 },
497             value               => 'yes',
498             explanation         => 'Barcode is auto-calculated',
499             type                => 'YesNo'
500         },
501         {
502             uniquefieldrequired => 'variable',
503             variable            => 'insecure',
504             forceupdate         => { 'explanation' => 1,
505                                      'type' => 1 },
506             value               => 'no',
507             explanation         =>
508 'If YES, no auth at all is needed. Be careful if you set this to yes!',
509             type                => 'YesNo'
510         },
511         {
512             uniquefieldrequired => 'variable',
513             variable            => 'authoritysep',
514             forceupdate         => { 'explanation' => 1,
515                                      'type' => 1,
516                                      'options' => 1 },
517             value               => '--',
518             explanation         =>
519             'the separator used in authority/thesaurus. Usually --',
520             type                => 'free',
521             options             => '10'
522         },
523         {
524             uniquefieldrequired => 'variable',
525             variable            => 'opaclanguages',
526             forceupdate         => { 'explanation' => 1,
527                                      'type' => 1 },
528             value               => 'en',
529             explanation         => 'Set the preferred order for translations.  The top language will be tried first.',
530             type                => 'Languages'
531         },
532         {
533             uniquefieldrequired => 'variable',
534             variable            => 'opacthemes',
535             forceupdate         => { 'explanation' => 1,
536                                      'type' => 1 },
537             value               => 'css',
538             explanation         => 'Set the preferred order for themes.  The top theme will be tried first.',
539             type                => 'Themes'
540         },
541         {
542             uniquefieldrequired => 'variable',
543             variable            => 'timeout',
544             forceupdate         => { 'explanation' => 1,
545                                      'type' => 1 },
546             value               => '1200',
547             explanation         => 'Inactivity timeout for cookies authentication (in seconds)',
548             type                => 'Integer'
549         },
550         {
551             uniquefieldrequired => 'variable',
552             variable            => 'marc',
553             forceupdate         => { 'explanation' => 1,
554                                      'type' => 1 },
555             value               => 'yes',
556             explanation         => 'Turn on MARC support',
557             type                => 'YesNo'
558         },
559         {
560             uniquefieldrequired => 'variable',
561             variable            => 'marcflavour',
562             forceupdate         => { 'explanation' => 1,
563                                      'type' => 1,
564                                      'options' => 1},
565             value               => 'MARC21',
566             explanation         =>
567             'your MARC flavor (MARC21 or UNIMARC) used for character encoding',
568             type                => 'Choice',
569             options             => 'MARC21|UNIMARC'
570         },
571         {
572             uniquefieldrequired => 'variable',
573             variable            => 'checkdigit',
574             value               => 'none',
575             forceupdate         => { 'explanation' => 1,
576                                      'type' => 1,
577                                      'options' => 1},
578             explanation         => 'Validity checks on membership number: none or "Katipo" style checks',
579             type                => 'Choice',
580             options             => 'none|katipo'
581         },
582         {
583             uniquefieldrequired => 'variable',
584             variable            => 'maxoutstanding',
585             forceupdate         => { 'explanation' => 1,
586                                      'type' => 1 },
587             value               => '5',
588             explanation         =>
589             'maximum amount withstanding to be able make reserves ',
590             type                => 'Integer'
591         },
592         {
593             uniquefieldrequired => 'variable',
594             variable            => 'maxreserves',
595             forceupdate         => { 'explanation' => 1,
596                                      'type' => 1 },
597             value               => '5',
598             explanation         =>
599             'maximum number of reserves a member can make',
600             type                => 'Integer'
601
602         },
603         {
604             uniquefieldrequired => 'variable',
605             variable            => 'noissuescharge',
606             forceupdate         => { 'explanation' => 1,
607                                      'type' => 1 },
608             value               => '5',
609             explanation         =>
610             'maximum amount withstanding to be able to check out an item',
611             type                => 'Integer'
612
613         },
614         {
615             uniquefieldrequired => 'variable',
616             variable            => 'KohaAdminEmailAddress',
617             forceupdate         => { 'explanation' => 1,
618                                      'type' => 1 },
619             value               => 'your.mail@here',
620             explanation => 'the email address where borrowers modifs are sent',
621             type                => 'free'
622         },
623         {
624             uniquefieldrequired => 'variable',
625             variable            => 'gist',
626             forceupdate         => { 'explanation' => 1,
627                                      'type' => 1 },
628             value               => '0.125',
629             explanation => 'the gist rate. NOT in %, but in numeric form (0.12 for 12%)',
630             type                => 'free'
631         },
632         {
633             uniquefieldrequired => 'variable',
634             variable            => 'ldapserver',
635             forceupdate         => { 'explanation' => 1,
636                                      'type' => 1 },
637             value               => '',
638             explanation => 'your ldap server',
639             type                => 'free'
640         },
641         {
642             uniquefieldrequired => 'variable',
643             variable            => 'ldapinfos',
644             forceupdate         => { 'explanation' => 1,
645                                      'type' => 1 },
646             value               => '',
647             explanation => 'ldap info. The ldap will be used in dn : uid=xxx, <ldapinfos>',
648             type                => 'free'
649         },
650         {
651             uniquefieldrequired => 'variable',
652             variable            => 'printcirculationslips',
653             forceupdate         => { 'explanation' => 1,
654                                      'type' => 1 },
655             value               => '0',
656             explanation => 'if set to 1, print circulation slips. If set to 0, don\'t',
657             type                => 'free'
658         },
659         {
660             uniquefieldrequired => 'variable',
661             variable            => 'suggestion',
662             forceupdate         => { 'explanation' => 1,
663                                      'type' => 1 },
664             value               => '0',
665             explanation => 'if set to 1, suggestions are activated in OPAC',
666             type                => 'free'
667         },
668         {
669             uniquefieldrequired => 'variable',
670             variable            => 'ISBD',
671             forceupdate         => { 'explanation' => 1,
672                                      'type' => 1 },
673             value               => 'Fill with appropriate value...',
674             explanation => 'ISBD',
675             type                => 'free'
676         },
677         {
678             uniquefieldrequired => 'variable',
679             variable            => 'virtualshelves',
680             forceupdate         => { 'explanation' => 1,
681                                      'type' => 1 },
682             value               => '0',
683             explanation => 'Set virtual shelves management ON or OFF',
684             type                => 'YesNo'
685         },
686     ],
687
688 );
689
690 my %fielddefinitions = (
691     printers => [
692         {
693             field   => 'printername',
694             type    => 'char(40)',
695             null    => '',
696             key     => 'PRI',
697             default => ''
698         },
699     ],
700     aqbookfund => [
701         {
702             field   => 'bookfundid',
703             type    => 'char(5)',
704             null    => '',
705             key     => 'PRI',
706             default => ''
707         },
708     ],
709     aqbudget => [
710         {
711             field   => 'aqbudgetid',
712             type    => 'tinyint(4)',
713             null    => '',
714             key     => 'PRI',
715                   default =>'',
716             extra => 'auto_increment'
717         },
718     ],
719     z3950servers => [
720         {
721             field   => 'id',
722             type    => 'int',
723             null    => '',
724             key     => 'PRI',
725             default => '',
726             extra   => 'auto_increment'
727         },
728     ],
729         marc_breeding => [
730         {
731             field   => 'z3950random',
732             type    => 'varchar(40)',
733             null    => 'NULL',
734             key     => '',
735             default => '',
736             extra   => ''
737         },
738         {
739             field   => 'encoding',
740             type    => 'varchar(40)',
741             null    => '',
742             key     => '',
743             default => '',
744             extra   => ''
745         },
746     ],
747 );
748
749 #-------------------
750 # Initialize
751
752 # Start checking
753
754 # Get version of MySQL database engine.
755 my $mysqlversion = `mysqld --version`;
756 $mysqlversion =~ /Ver (\S*) /;
757 $mysqlversion = $1;
758 if ( $mysqlversion ge '3.23' ) {
759     print "Could convert to MyISAM database tables...\n";
760 }
761
762 #---------------------------------
763 # Tables
764
765 # Collect all tables into a list
766 $sth = $dbh->prepare("show tables");
767 $sth->execute;
768 while ( my ($table) = $sth->fetchrow ) {
769     $existingtables{$table} = 1;
770 }
771
772
773 # Now add any missing tables
774 foreach $table ( keys %requiretables ) {
775     unless ( $existingtables{$table} ) {
776         print "Adding $table table...\n";
777         my $sth = $dbh->prepare("create table $table $requiretables{$table}");
778         $sth->execute;
779         if ( $sth->err ) {
780             print "Error : $sth->errstr \n";
781             $sth->finish;
782         }    # if error
783     }    # unless exists
784 }    # foreach
785
786 # now drop useless tables
787 foreach $table ( keys %dropable_table ) {
788         if ( $existingtables{$table} ) {
789                 print "Dropping unused table $table\n" if $debug;
790                 $dbh->do("drop table $table");
791                 if ( $dbh->err ) {
792                         print "Error : $dbh->errstr \n";
793                 }
794         }
795 }
796 unless ( $existingtables{'z3950servers'} ) {
797         #MJR: added syntax entries to close bug 624
798     print "Adding z3950servers table...\n";
799     my $sti = $dbh->prepare( "create table z3950servers (
800                                                                                 host char(255),
801                                                                                 port int,
802                                                                                 db char(255),
803                                                                                 userid char(255),
804                                                                                 password char(255),
805                                                                                 name text,
806                                                                                 id int,
807                                                                                 checked smallint,
808                                                                                 rank int,
809                                                                                 syntax char(80))"
810     );
811     $sti->execute;
812     $sti = $dbh->prepare( "insert into z3950servers
813                                                                 values ('z3950.loc.gov',
814                                                                 7090,
815                                                                 'voyager',
816                                                                 '', '',
817                                                                 'Library of Congress',
818                                                                 1, 1, 1, 'USMARC')"
819     );
820     $sti->execute;
821 }
822 unless ( $existingtables{'issuingrules'} ) {
823         $dbh->do("alter table categoryitem rename issuingrules");
824         print "renaming categoryitem\n";
825 }
826
827
828 #---------------------------------
829 # Columns
830
831 foreach $table ( keys %requirefields ) {
832     print "Check table $table\n" if $debug;
833     $sth = $dbh->prepare("show columns from $table");
834     $sth->execute();
835     undef %types;
836     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
837     {
838         $types{$column} = $type;
839     }    # while
840     foreach $column ( keys %{ $requirefields{$table} } ) {
841         print "  Check column $column  [$types{$column}]\n" if $debug;
842         if ( !$types{$column} ) {
843
844             # column doesn't exist
845             print "Adding $column field to $table table...\n";
846             $query = "alter table $table
847                         add column $column " . $requirefields{$table}->{$column};
848             print "Execute: $query\n" if $debug;
849             my $sti = $dbh->prepare($query);
850             $sti->execute;
851             if ( $sti->err ) {
852                 print "**Error : $sti->errstr \n";
853                 $sti->finish;
854             }    # if error
855         }    # if column
856     }    # foreach column
857 }    # foreach table
858
859 foreach $table ( keys %fielddefinitions ) {
860         print "Check table $table\n" if $debug;
861         $sth = $dbh->prepare("show columns from $table");
862         $sth->execute();
863         my $definitions;
864         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
865         {
866                 $definitions->{$column}->{type}    = $type;
867                 $definitions->{$column}->{null}    = $null;
868                 $definitions->{$column}->{key}     = $key;
869                 $definitions->{$column}->{default} = $default;
870                 $definitions->{$column}->{extra}   = $extra;
871         }    # while
872         my $fieldrow = $fielddefinitions{$table};
873         foreach my $row (@$fieldrow) {
874                 my $field   = $row->{field};
875                 my $type    = $row->{type};
876                 my $null    = $row->{null};
877                 my $key     = $row->{key};
878                 my $default = $row->{default};
879                 $default="''" unless $default;
880                 my $extra   = $row->{extra};
881                 my $def     = $definitions->{$field};
882                 unless ( $type eq $def->{type}
883                         && $null eq $def->{null}
884                         && $key eq $def->{key}
885                         && $default eq $def->{default}
886                         && $extra eq $def->{extra} )
887                 {
888
889                         if ( $null eq '' ) {
890                                 $null = 'NOT NULL';
891                         }
892                         if ( $key eq 'PRI' ) {
893                                 $key = 'PRIMARY KEY';
894                         }
895                         unless ( $extra eq 'auto_increment' ) {
896                                 $extra = '';
897                         }
898                         # if it's a new column use "add", if it's an old one, use "change".
899                         my $action;
900                         if ($definitions->{$field}->{type}) {
901                                 $action="change $field"
902                         } else {
903                                 $action="add";
904                         }
905 # if it's a primary key, drop the previous pk, before altering the table
906                         my $sth;
907                         if ($key ne 'PRIMARY KEY') {
908                                 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
909                         } else {
910                                 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
911                         }
912                         $sth->execute($default);
913                         print "  Alter $field in $table\n";
914                 }
915         }
916 }
917
918 # Get list of columns from borrowers table
919 my %itemtypes;
920 my %nullenabled;
921 $sth = $dbh->prepare("show columns from borrowers");
922 $sth->execute;
923 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
924 {
925     $itemtypes{$column} = $type;
926     $nullenabled{$column} = $null;
927 }
928
929 unless ( $itemtypes{'cardnumber'} eq 'varchar(20)' ) {
930     $itemtypes{'cardnumber'} =~ /varchar\((\d+)\)/;
931     my $oldlength = $1;
932     if ( $oldlength < 16 ) {
933         print "Setting maximum cardnumber length to 16 (was $oldlength) and marking unique.\n";
934         my $sti =
935           $dbh->prepare(
936             "alter table borrowers change cardnumber cardnumber varchar(16)");
937         $sti->execute;
938         $sti->finish;
939         $sti =
940           $dbh->prepare(
941             "alter table borrowers drop index cardnumber");
942         $sti->execute;
943         $sti->finish;
944         $sti =
945           $dbh->prepare(
946             "alter table borrowers add unique(cardnumber)");
947         $sti->execute;
948         $sti->finish;
949     }
950 }
951 #
952 # Get list of columns from items table
953 $sth = $dbh->prepare("show columns from items");
954 $sth->execute;
955 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
956 {
957     $itemtypes{$column} = $type;
958     $nullenabled{$column} = $null;
959 }
960
961 unless ( $itemtypes{'barcode'} eq 'varchar(20)' ) {
962     $itemtypes{'barcode'} =~ /varchar\((\d+)\)/;
963     my $oldlength = $1;
964     if ( $oldlength < 20 ) {
965         print "Setting maximum barcode length to 20 (was $oldlength).\n";
966         my $sti =
967           $dbh->prepare(
968             "alter table items change barcode barcode varchar(20)");
969         $sti->execute;
970     }
971 }
972 #
973 # dropping unique barcode index & setting barcode to null allowed.
974 #
975 $sth = $dbh->prepare("show index from items");
976 $sth->execute;
977 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
978 {
979         if ($key_name eq 'barcode' && $non_unique eq 0) {
980                 print "dropping BARCODE index to enable empty barcodes\n";
981                 $dbh->do("ALTER TABLE `items` DROP INDEX `barcode`");
982         }
983 }
984 $dbh->do("ALTER TABLE `items` CHANGE `barcode` `barcode` VARCHAR( 20 )") unless ($nullenabled{barcode} eq 'YES');
985
986 #
987 # creating fulltext index in bibliothesaurus if needed
988 #
989 $sth = $dbh->prepare("show index from bibliothesaurus");
990 $sth->execute;
991 my $exists=0;
992 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
993 {
994         if ($key_name eq 'category_2') {
995                 $exists=1;
996         }
997 }
998 print "Creating fulltext index on bibliothesaurus\n" unless $exists;
999 $dbh->do('create fulltext index category_2 on bibliothesaurus (category,freelib)') unless $exists;
1000
1001 #
1002 # creating  index in z3950results if needed
1003 #
1004 $sth = $dbh->prepare("show index from z3950results");
1005 $sth->execute;
1006 my $exists=0;
1007 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1008 {
1009         if ($key_name eq 'query_server') {
1010                 $exists=1;
1011         }
1012 }
1013 print "Creating  index on z3950results\n" unless $exists;
1014 $dbh->do('create unique index query_server on z3950results (queryid,server)') unless $exists;
1015
1016 # changing z3950daemon field to NULL in marc_breeding
1017 $dbh->do("ALTER TABLE `marc_breeding` CHANGE `z3950random` `z3950random` VARCHAR( 40 )");
1018
1019 # making borrowernumber an auto_increment field
1020 $dbh->do("ALTER TABLE `borrowers` CHANGE `borrowernumber` `borrowernumber` INTEGER auto_increment");
1021
1022 # changing indexes in marc_*_structure to use frameworkcode
1023 $dbh->do('alter table marc_subfield_structure drop index tab');
1024 $dbh->do('create index tab on marc_subfield_structure (frameworkcode,tab)');
1025 $dbh->do('alter table marc_subfield_structure drop index kohafield');
1026 $dbh->do('create index kohafield on marc_subfield_structure (frameworkcode,kohafield)');
1027
1028
1029 # extending the timestamp in branchtransfers...
1030 my %branchtransfers;
1031
1032 $sth = $dbh->prepare("show columns from branchtransfers");
1033 $sth->execute;
1034 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1035 {
1036     $branchtransfers{$column} = $type;
1037 }
1038
1039 unless ( $branchtransfers{'datesent'} eq 'datetime' ) {
1040     print "Setting type of datesent in branchtransfers to datetime.\n";
1041     my $sti =
1042       $dbh->prepare(
1043         "alter table branchtransfers change datesent datesent datetime");
1044     $sti->execute;
1045 }
1046
1047 unless ( $branchtransfers{'datearrived'} eq 'datetime' ) {
1048     print "Setting type of datearrived in branchtransfers to datetime.\n";
1049     my $sti =
1050       $dbh->prepare(
1051         "alter table branchtransfers change datearrived datearrived datetime");
1052     $sti->execute;
1053 }
1054
1055 # changing the branchcategories table around...
1056 my %branchcategories;
1057
1058 $sth = $dbh->prepare("show columns from branchcategories");
1059 $sth->execute;
1060 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1061 {
1062     $branchcategories{$column} = $type;
1063 }
1064
1065 unless ( $branchcategories{'categorycode'} eq 'varchar(4)' ) {
1066     print
1067 "Setting type of categorycode in branchcategories to varchar(4),\n and making the primary key.\n";
1068     my $sti =
1069       $dbh->prepare(
1070 "alter table branchcategories change categorycode categorycode varchar(4) not null"
1071     );
1072     $sti->execute;
1073     $sti =
1074       $dbh->prepare(
1075         "alter table branchcategories add primary key (categorycode)");
1076     $sti->execute;
1077 }
1078
1079 unless ( $branchcategories{'categoryname'} eq 'text' ) {
1080     print "Changing branchcode in branchcategories to categoryname text.\n";
1081     my $sth =
1082       $dbh->prepare(
1083         "alter table branchcategories change branchcode categoryname text");
1084     $sth->execute;
1085 }
1086
1087 unless ( $branchcategories{'codedescription'} eq 'text' ) {
1088     print
1089 "Replacing branchholding in branchcategories with codedescription text.\n";
1090     my $sth =
1091       $dbh->prepare(
1092         "alter table branchcategories change branchholding codedescription text"
1093     );
1094     $sth->execute;
1095 }
1096
1097 # changing the items table around...
1098 my %items;
1099
1100 $sth = $dbh->prepare("show columns from items");
1101 $sth->execute;
1102 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1103 {
1104     $items{$column} = $type;
1105 }
1106
1107 if ($items{'bulk'} eq "varchar(30)") {
1108     print "  Setting callnumber in items table\n";
1109     my $sti =
1110       $dbh->prepare("ALTER TABLE `items` CHANGE `bulk` `itemcallnumber` VARCHAR( 30 ) DEFAULT NULL");
1111     $sti->execute;
1112     $sti = $dbh->prepare("update marc_subfield_structure set kohafield=\"items.itemcallnumber\" where kohafield=\"items.bulk\"");
1113     $sti->execute;
1114 }
1115
1116 # changing the marc_subfield_structure table around...
1117 my %marc_subfield_structure;
1118
1119 $sth = $dbh->prepare("show columns from marc_subfield_structure");
1120 $sth->execute;
1121 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1122 {
1123     $marc_subfield_structure{$column} = $type;
1124 }
1125
1126 if ($marc_subfield_structure{thesaurus_category}) {
1127     print "  changing thesaurus_category in marc_subfield_structure table\n";
1128     my $sti =
1129       $dbh->prepare("ALTER TABLE marc_subfield_structure CHANGE `thesaurus_category` `authtypecode` VARCHAR(10 ) DEFAULT NULL");
1130     $sti->execute;
1131 }
1132
1133 #
1134 # creating  index in issuingrules if needed
1135 #
1136 $sth = $dbh->prepare("show index from issuingrules");
1137 $sth->execute;
1138 my $exists=0;
1139 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1140 {
1141         if ($key_name eq 'PRIMARY') {
1142                 $exists=1;
1143         }
1144 }
1145 print "Creating  index on z3950results\n" unless $exists;
1146 $dbh->do('ALTER TABLE issuingrules ADD PRIMARY KEY ( branchcode, categorycode, itemtype )') unless $exists;
1147
1148 $dbh->do('ALTER TABLE marc_tag_structure drop primary key');
1149 $dbh->do('ALTER TABLE marc_tag_structure ADD PRIMARY KEY ( frameworkcode, tagfield )');
1150
1151 $dbh->do('ALTER TABLE marc_subfield_structure drop primary key');
1152 $dbh->do('ALTER TABLE marc_subfield_structure ADD PRIMARY KEY ( frameworkcode, tagfield, tagsubfield )');
1153
1154 # Get list of columns from marc_word table
1155 my %marc_word;
1156 my %nullenabled;
1157 $sth = $dbh->prepare("show columns from marc_word");
1158 $sth->execute;
1159 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1160 {
1161     $marc_word{$column} = $type;
1162     $nullenabled{$column} = $null;
1163 }
1164 if ($marc_word{subfieldid}) {
1165         #create field tagsubfield, copy tag+subfieldid, then drop tag and subfieldid
1166         print "Modifying marc_word (concat on tag and subfield for better perfs)\n";
1167         $dbh->do("ALTER TABLE `marc_word` ADD `tagsubfield` CHAR( 4 ) NOT NULL AFTER `bibid`");
1168         $dbh->do("update marc_word set tagsubfield=concat(tag,subfieldid)");
1169         $dbh->do("alter table marc_word drop tag");
1170         $dbh->do("alter table marc_word drop subfieldid");
1171 }
1172 # Populate tables with required data
1173
1174 foreach my $table ( keys %tabledata ) {
1175     print "Checking for data required in table $table...\n";
1176     my $tablerows = $tabledata{$table};
1177     foreach my $row (@$tablerows) {
1178         my $uniquefieldrequired = $row->{uniquefieldrequired};
1179         my $uniquevalue         = $row->{$uniquefieldrequired};
1180         my $forceupdate         = $row->{forceupdate};
1181         my $sth                 =
1182           $dbh->prepare(
1183 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1184         );
1185         $sth->execute($uniquevalue);
1186         if ($sth->rows) {
1187             foreach my $field (keys %$forceupdate) {
1188                 if ($forceupdate->{$field}) {
1189                     my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1190                     $sth->execute($row->{$field}, $uniquevalue);
1191                 }
1192             }
1193         } else {
1194             print "Adding row to $table: ";
1195             my @values;
1196             my $fieldlist;
1197             my $placeholders;
1198             foreach my $field ( keys %$row ) {
1199                 next if $field eq 'uniquefieldrequired';
1200                 next if $field eq 'forceupdate';
1201                 my $value = $row->{$field};
1202                 push @values, $value;
1203                 print "  $field => $value";
1204                 $fieldlist .= "$field,";
1205                 $placeholders .= "?,";
1206             }
1207             print "\n";
1208             $fieldlist    =~ s/,$//;
1209             $placeholders =~ s/,$//;
1210             my $sth =
1211               $dbh->prepare(
1212                 "insert into $table ($fieldlist) values ($placeholders)");
1213             $sth->execute(@values);
1214         }
1215     }
1216 }
1217
1218 $sth->finish;
1219
1220 exit;
1221
1222 # $Log$
1223 # Revision 1.84  2004/06/17 08:25:21  tipaul
1224 # DB modifs : merging tag & subfield in marc_word table
1225 #
1226 # Revision 1.83  2004/06/10 08:32:02  tipaul
1227 # MARC authority management (continued)
1228 #
1229 # Revision 1.82  2004/06/03 12:46:58  tipaul
1230 # * frameworks and itemtypes are independant
1231 #
1232 # WARNING : will work only if applied to a 2.0 base. some modifs have been done since last commit that will NOT be applied if you run updatedatabase again.
1233 #
1234 # Revision 1.81  2004/05/28 09:56:21  tipaul
1235 # bugfix
1236 #
1237 # Revision 1.80  2004/05/28 08:32:00  tipaul
1238 # adding :
1239 # * MARC authority file
1240 # * seealso & hidden in MARC biblio structure.
1241 #
1242 # Revision 1.79  2004/05/18 09:50:07  tipaul
1243 # *** empty log message ***
1244 #
1245 # Revision 1.78  2004/05/10 09:29:33  tipaul
1246 # css is now the default theme for OPAC.
1247 # It will be the theme used for improvements and new things in OPAC.
1248 #
1249 # Revision 1.77  2004/05/06 14:56:51  tipaul
1250 # adding table issuingrules (previously called categoryitem
1251 #
1252 # Revision 1.76  2004/05/03 09:32:25  tipaul
1253 # adding printcirculationsplit parameter (already existed, but was not in systempref by defaul)
1254 #
1255 # Revision 1.75  2004/04/14 19:49:00  tipaul
1256 # seealso field set to 255 chars
1257 #
1258 # Revision 1.74  2004/03/11 16:10:16  tipaul
1259 # *** empty log message ***
1260 #
1261 # Revision 1.73  2004/03/06 20:26:13  tipaul
1262 # adding seealso feature in MARC searches
1263 #