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