Adding an object field to action_logs.
[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 use lib "/usr/koha200pre2/modules";
16 use strict;
17
18 # CPAN modules
19 use DBI;
20 use Getopt::Long;
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 $silent;
41 GetOptions(
42         's' =>\$silent
43         );
44 my $dbh = C4::Context->dbh;
45 print "connected to your DB. Checking & modifying it\n" unless $silent;
46
47 #-------------------
48 # Defines
49
50 # Tables to add if they don't exist
51 my %requiretables = (
52     shelfcontents => "( shelfnumber int not null,
53                                                         itemnumber int not null,
54                                                         flags int)",
55     bookshelf => "( shelfnumber int auto_increment primary key,
56                                                 shelfname char(255))",
57     z3950queue => "( id int auto_increment primary key,
58                                                 term text,
59                                                 type char(10),
60                                                 startdate int,
61                                                 enddate int,
62                                                 done smallint,
63                                                 results longblob,
64                                                 numrecords int,
65                                                 servers text,
66                                                 identifier char(30))",
67     z3950results => "( id int auto_increment primary key,
68                                                 queryid int,
69                                                 server char(255),
70                                                 startdate int,
71                                                 enddate int,
72                                                 results longblob,
73                                                 numrecords int,
74                                                 numdownloaded int,
75                                                 highestseen int,
76                                                 active smallint)",
77     branchrelations => "( branchcode varchar(4),
78                                                         categorycode varchar(4))",
79     websites => "( websitenumber int(11) NOT NULL auto_increment,
80                                                 biblionumber int(11) NOT NULL default '0',
81                                                 title text,
82                                                 description text,
83                                                 url varchar(255),
84                                                 PRIMARY KEY (websitenumber) )",
85     marcrecorddone => "( isbn char(40),
86                                                                 issn char(40),
87                                                                 lccn char(40),
88                                                                 controlnumber char(40))",
89     uploadedmarc => "( id int(11) NOT NULL auto_increment PRIMARY KEY,
90                                                         marc longblob,
91                                                         hidden smallint(6) default NULL,
92                                                         name varchar(255) default NULL)",
93     ethnicity => "( code varchar(10) NOT NULL default '',
94                                         name varchar(255) default NULL,
95                                         PRIMARY KEY  (code)   )",
96     sessions => "( sessionID varchar(255) NOT NULL default '',
97                                                 userid varchar(255) default NULL,
98                                                 ip varchar(16) default NULL,
99                                                 lasttime int,
100                                                 PRIMARY KEY (sessionID)   )",
101     sessionqueries => "( sessionID varchar(255) NOT NULL default '',
102                                                                 userid char(100) NOT NULL default '',
103                                                                 ip char(18) NOT NULL default '',
104                                                                 url text NOT NULL default ''  )",
105     bibliothesaurus => "( id bigint(20) NOT NULL auto_increment,
106                                                         freelib char(255) NOT NULL default '',
107                                                         stdlib char(255) NOT NULL default '',
108                                                         category char(10) NOT NULL default '',
109                                                         level tinyint(4) NOT NULL default '1',
110                                                         hierarchy char(80) NOT NULL default '',
111                                                         father char(80) NOT NULL default '',
112                                                         PRIMARY KEY  (id),
113                                                         KEY freelib (freelib),
114                                                         KEY stdlib (stdlib),
115                                                         KEY category (category),
116                                                         KEY hierarchy (hierarchy)
117                                                         )",
118     marc_biblio => "(
119                                                 bibid bigint(20) unsigned NOT NULL auto_increment,
120                                                 biblionumber int(11) NOT NULL default '0',
121                                                 datecreated date NOT NULL default '0000-00-00',
122                                                 datemodified date default NULL,
123                                                 origincode char(20) default NULL,
124                                                 PRIMARY KEY  (bibid),
125                                                 KEY origincode (origincode),
126                                                 KEY biblionumber (biblionumber)
127                                                 ) ",
128     marc_blob_subfield => "(
129                                         blobidlink bigint(20) NOT NULL auto_increment,
130                                         subfieldvalue longtext NOT NULL,
131                                         PRIMARY KEY  (blobidlink)
132                                         ) ",
133     marc_subfield_structure => "(
134                                                 tagfield char(3) NOT NULL default '',
135                                                 tagsubfield char(1) NOT NULL default '',
136                                                 liblibrarian char(255) NOT NULL default '',
137                                                 libopac char(255) NOT NULL default '',
138                                                 repeatable tinyint(4) NOT NULL default '0',
139                                                 mandatory tinyint(4) NOT NULL default '0',
140                                                 kohafield char(40)  default NULL,
141                                                 tab tinyint(1) default NULL,
142                                                 authorised_value char(10) default NULL,
143                                                 thesaurus_category char(10) default NULL,
144                                                 value_builder char(80) default NULL,
145                                                 PRIMARY KEY  (tagfield,tagsubfield),
146                                                 KEY kohafield (kohafield),
147                                                 KEY tab (tab)
148                                                 )",
149     marc_subfield_table => "(
150                                                 subfieldid bigint(20) unsigned NOT NULL auto_increment,
151                                                 bibid bigint(20) unsigned NOT NULL default '0',
152                                                 tag char(3) NOT NULL default '',
153                                                 tagorder tinyint(4) NOT NULL default '1',
154                                                 tag_indicator char(2) NOT NULL default '',
155                                                 subfieldcode char(1) NOT NULL default '',
156                                                 subfieldorder tinyint(4) NOT NULL default '1',
157                                                 subfieldvalue varchar(255) default NULL,
158                                                 valuebloblink bigint(20) default NULL,
159                                                 PRIMARY KEY  (subfieldid),
160                                                 KEY bibid (bibid),
161                                                 KEY tag (tag),
162                                                 KEY tag_indicator (tag_indicator),
163                                                 KEY subfieldorder (subfieldorder),
164                                                 KEY subfieldcode (subfieldcode),
165                                                 KEY subfieldvalue (subfieldvalue),
166                                                 KEY tagorder (tagorder)
167                                         )",
168     marc_tag_structure => "(
169                                         tagfield char(3) NOT NULL default '',
170                                         liblibrarian char(255) NOT NULL default '',
171                                         libopac char(255) NOT NULL default '',
172                                         repeatable tinyint(4) NOT NULL default '0',
173                                         mandatory tinyint(4) NOT NULL default '0',
174                                         authorised_value char(10) default NULL,
175                                         PRIMARY KEY  (tagfield)
176                                         )",
177     marc_word => "(
178                                 bibid bigint(20) NOT NULL default '0',
179                                 tag char(3) NOT NULL default '',
180                                 tagorder tinyint(4) NOT NULL default '1',
181                                 subfieldid char(1) NOT NULL default '',
182                                 subfieldorder tinyint(4) NOT NULL default '1',
183                                 word varchar(255) NOT NULL default '',
184                                 sndx_word varchar(255) NOT NULL default '',
185                                 KEY bibid (bibid),
186                                 KEY tag (tag),
187                                 KEY tagorder (tagorder),
188                                 KEY subfieldid (subfieldid),
189                                 KEY subfieldorder (subfieldorder),
190                                 KEY word (word),
191                                 KEY sndx_word (sndx_word)
192                         )",
193     marc_breeding => "(  id bigint(20) NOT NULL auto_increment,
194                                 file varchar(80) NOT NULL default '',
195                                 isbn varchar(10) NOT NULL default '',
196                                 title varchar(128) default NULL,
197                                 author varchar(80) default NULL,
198                                 marc text NOT NULL,
199                                 encoding varchar(40) default NULL,
200                                 PRIMARY KEY  (id),
201                                 KEY title (title),
202                                 KEY isbn (isbn)
203                         )",
204     authorised_values => "(id int(11) NOT NULL auto_increment,
205                                 category char(10) NOT NULL default '',
206                                 authorised_value char(80) NOT NULL default '',
207                                 lib char(80) NULL,
208                                 PRIMARY KEY  (id),
209                                 KEY name (category)
210                         )",
211     userflags => "( bit int(11) NOT NULL default '0',
212                                 flag char(30), flagdesc char(255),
213                                 defaulton int(11)
214                         )",
215         auth_types => "(
216                                         authtypecode char(10) not NULL,
217                                         authtypetext char(255) not NULL,
218                                         auth_tag_to_report char(3) not NULL,
219                                         summary text not NULL,
220                                         PRIMARY KEY (authtypecode)
221                         )",
222         biblio_framework => "(
223                                         frameworkcode char(4) not NULL,
224                                         frameworktext char(255) not NULL,
225                                         PRIMARY KEY (frameworkcode)
226                         )",
227     auth_subfield_structure => "(
228                                         authtypecode char(10) NOT NULL default '',
229                                         tagfield char(3) NOT NULL default '',
230                                         tagsubfield char(1) NOT NULL default '',
231                                         liblibrarian char(255) NOT NULL default '',
232                                         libopac char(255) NOT NULL default '',
233                                         repeatable tinyint(4) NOT NULL default '0',
234                                         mandatory tinyint(4) NOT NULL default '0',
235                                         tab tinyint(1) default NULL,
236                                         authorised_value char(10) default NULL,
237                                         value_builder char(80) default NULL,
238                                         seealso char(255) default NULL,
239                                         PRIMARY KEY  (authtypecode,tagfield,tagsubfield),
240                                         KEY tab (authtypecode,tab)
241                                         )",
242     auth_tag_structure => "(
243                                         authtypecode char(10) NOT NULL default '',
244                                         tagfield char(3) NOT NULL default '',
245                                         liblibrarian char(255) NOT NULL default '',
246                                         libopac char(255) NOT NULL default '',
247                                         repeatable tinyint(4) NOT NULL default '0',
248                                         mandatory tinyint(4) NOT NULL default '0',
249                                         authorised_value char(10) default NULL,
250                                         PRIMARY KEY  (authtypecode,tagfield)
251                                         )",
252     auth_header => "(
253                                                 authid bigint(20) unsigned NOT NULL auto_increment,
254                                                 authtypecode char(10) NOT NULL default '',
255                                                 datecreated date NOT NULL default '0000-00-00',
256                                                 datemodified date default NULL,
257                                                 origincode char(20) default NULL,
258                                                 PRIMARY KEY  (authid),
259                                                 KEY origincode (origincode)
260                                                 ) ",
261     auth_subfield_table => "(
262                                                 subfieldid bigint(20) unsigned NOT NULL auto_increment,
263                                                 authid bigint(20) unsigned NOT NULL default '0',
264                                                 tag char(3) NOT NULL default '',
265                                                 tagorder tinyint(4) NOT NULL default '1',
266                                                 tag_indicator char(2) NOT NULL default '',
267                                                 subfieldcode char(1) NOT NULL default '',
268                                                 subfieldorder tinyint(4) NOT NULL default '1',
269                                                 subfieldvalue varchar(255) default NULL,
270                                                 PRIMARY KEY  (subfieldid),
271                                                 KEY authid (authid),
272                                                 KEY tag (tag),
273                                                 KEY subfieldcode (subfieldcode),
274                                                 KEY subfieldvalue (subfieldvalue)
275                                         )",
276     auth_word => "(
277                                 authid bigint(20) NOT NULL default '0',
278                                 tagsubfield char(4) NOT NULL default '',
279                                 tagorder tinyint(4) NOT NULL default '1',
280                                 subfieldorder tinyint(4) NOT NULL default '1',
281                                 word varchar(255) NOT NULL default '',
282                                 sndx_word varchar(255) NOT NULL default '',
283                                 KEY authid (authid),
284                                 KEY marc_search (tagsubfield,word),
285                                 KEY word (word),
286                                 KEY sndx_word (sndx_word)
287                         )",
288         suggestions => "(
289                                 suggestionid int(8) NOT NULL auto_increment,
290                                 suggestedby int(11) NOT NULL default '0',
291                                 managedby int(11) default NULL ,
292                                 STATUS varchar(10) NOT NULL default '',
293                                 note text,
294                                 author varchar(80) default NULL ,
295                                 title varchar(80) default NULL ,
296                                 copyrightdate smallint(6) default NULL ,
297                                 publishercode varchar(255) default NULL ,
298                                 date timestamp(8) NOT NULL ,
299                                 volumedesc varchar(255) default NULL ,
300                                 publicationyear smallint(6) default '0',
301                                 place varchar(255) default NULL ,
302                                 isbn varchar(10) default NULL ,
303                                 mailoverseeing smallint(1) default '0',
304                                 biblionumber int(11) default NULL ,
305                                 PRIMARY KEY (suggestionid) ,
306                                 KEY suggestedby(suggestedby) ,
307                                 KEY managedby(managedby)
308                         )",
309         aqbasket => "(basketno int(11) NOT NULL auto_increment,
310                                 creationdate date,
311                                 closedate date,
312                                 booksellerid varchar(10),
313                                 authorisedby varchar(10),
314                                 booksellerinvoicenumber text,
315                                 PRIMARY KEY (basketno)
316                                 )",
317         serial => "(serialid int(11) NOT NULL auto_increment,
318                                 biblionumber varchar(100) NOT NULL default '',
319                                 subscriptionid varchar(100) NOT NULL default '',
320                                 serialseq varchar(100) NOT NULL default '',
321                                 status tinyint(4) NOT NULL default '0',
322                                 planneddate date NOT NULL default '0000-00-00',
323                                 PRIMARY KEY  (serialid)
324                                 )",
325         subscription => "(biblionumber int(11) NOT NULL default '0',
326                                                 subscriptionid int(11) NOT NULL auto_increment,
327                                                 librarian varchar(100) default '',
328                                                 startdate date default '0000-00-00',
329                                                 aqbooksellerid int(11) default '0',
330                                                 cost int(11) default '0',
331                                                 aqbudgetid int(11) default '0',
332                                                 weeklength tinyint(4) default '0',
333                                                 monthlength tinyint(4) default '0',
334                                                 numberlength tinyint(4) default '0',
335                                                 periodicity tinyint(4) default '0',
336                                                 dow varchar(100) default '',
337                                                 numberingmethod varchar(100) default '',
338                                                 notes text,
339                                                 status varchar(100) NOT NULL default '',
340                                                 add1 int(11) default 0,
341                                                 every1 int(11) default 0,
342                                                 whenmorethan1 int(11) default 0,
343                                                 setto1 int(11),
344                                                 lastvalue1 int(11),
345                                                 add2 int(11) default 0,
346                                                 every2 int(11) default 0,
347                                                 whenmorethan2 int(11) default 0,
348                                                 setto2 int(11),
349                                                 lastvalue2 int(11),
350                                                 add3 int(11) default 0,
351                                                 every3 int(11) default 0,
352                                                 innerloop1 int(11) default 0,
353                                                 innerloop2 int(11) default 0,
354                                                 innerloop3 int(11) default 0,
355                                                 whenmorethan3 int(11) default 0,
356                                                 setto3 int(11),
357                                                 lastvalue3 int(11),
358                                                 PRIMARY KEY  (subscriptionid)
359                                                 )",
360         subscriptionhistory => "(biblionumber int(11) NOT NULL default '0',
361                                                         subscriptionid int(11) NOT NULL default '0',
362                                                         histstartdate date NOT NULL default '0000-00-00',
363                                                         enddate date default '0000-00-00',
364                                                         missinglist longtext NOT NULL,
365                                                         recievedlist longtext NOT NULL,
366                                                         opacnote varchar(150) NOT NULL default '',
367                                                         librariannote varchar(150) NOT NULL default '',
368                                                         PRIMARY KEY  (subscriptionid),
369                                                         KEY biblionumber (biblionumber)
370                                                 )",
371     categorytable       => "(categorycode char(5) NOT NULL default '',
372                              description text default '',
373                              itemtypecodes text default '',
374                              PRIMARY KEY (categorycode)
375                             )",
376     subcategorytable       => "(subcategorycode char(5) NOT NULL default '',
377                              description text default '',
378                              itemtypecodes text default '',
379                              PRIMARY KEY (subcategorycode)
380                             )",
381     mediatypetable       => "(mediatypecode char(5) NOT NULL default '',
382                              description text default '',
383                              itemtypecodes text default '',
384                              PRIMARY KEY (mediatypecode)
385                             )",
386     `action_logs`       => "(
387                                     `timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL ,
388                                     `user` INT( 11 ) NOT NULL ,
389                                     `module` TEXT default '',
390                                     `action` TEXT default '' ,
391                                     `object` INT(11) default '' ,
392                                     `info` TEXT default '' ,
393                                     PRIMARY KEY ( `timestamp` , `user` )
394                             )",
395 );
396
397 my %requirefields = (
398     biblio        => { 'abstract' => 'text' },
399     deletedbiblio => { 'abstract' => 'text', 'marc' => 'blob' },
400     deleteditems => { 'marc' => 'blob', 'paidfor' => 'text', 'location' => 'varchar(80)'},
401     biblioitems   => {
402         'lccn' => 'char(25)',
403         'url'  => 'varchar(255)',
404         'marc' => 'text'
405     },
406     deletedbiblioitems => {
407         'lccn' => 'char(25)',
408         'url'  => 'varchar(255)',
409         'marc' => 'text'
410     },
411     branchtransfers => { 'datearrived'    => 'datetime' },
412     statistics      => { 'borrowernumber' => 'int(11)' },
413     aqbooksellers   => {
414         'invoicedisc' => 'float(6,4)',
415         'nocalc'      => 'int(11)'
416     },
417     borrowers => {
418                 'userid'        => 'char(30)',
419                 'password'      => 'char(30)',
420                 'flags'         => 'int(11)',
421                 'textmessaging' => 'varchar(30)',
422                 'zipcode' => 'varchar(25)',
423                 'homezipcode' => 'varchar(25)',
424                 'sort1' => 'char(80)',
425                 'sort2' => 'char(80)',
426     },
427     aqorders => { 'budgetdate' => 'date',
428                                 'sort1' => 'char(80)',
429                                 'sort2' => 'char(80)', },
430     aqbookfund =>{'branchcode'=> 'varchar(4) NULL'},
431     aqbudget => {'aqbudgetid' => 'tinyint(4) auto_increment primary key', 'branchcode'=> 'varchar(4) NULL'},
432     items => {'paidfor' => 'text', 'location' => 'char(80)'},
433
434     #added so that reference items are not available for reserves...
435     itemtypes         => { 'notforloan'  => 'smallint(6)' },
436     systempreferences => { 'explanation' => 'char(80)',
437                            'type' => 'char(20)',
438                            'options' => 'text' },
439     z3950servers      => { 'syntax'      => 'char(80)' },
440         marc_tag_structure =>{
441                                                         'frameworkcode' => 'char(4) not NULL default \'\''},
442     marc_subfield_structure =>{'seealso'  => 'char(255)',
443                                                         'frameworkcode' => 'char(4) not NULL default \'\'',
444                                                         'hidden' => 'tinyint(1)',
445                                                         'isurl' => 'tinyint(1)',
446                                                         'link' => 'char(80)',
447                                                         },
448     bookshelf => {'owner' => 'char(80)',
449                                         'category' => 'char(1)',
450                                 },
451     marc_biblio        => { 'frameworkcode' => 'char(4) not NULL default \'\'' },
452 );
453
454 my %dropable_table = (
455     classification => 'classification',
456     multipart      => 'multipart',
457     multivolume    => 'multivolume',
458     newitems       => 'newitems',
459     procedures     => 'procedures',
460     publisher      => 'publisher',
461     searchstats    => 'searchstats',
462     serialissues   => 'serialissues',
463 );
464
465 my %uselessfields = (
466         aqorders => "requisitionedby,authorisedby,booksellerid,
467                         deliverydays,followupdays,
468                         numberfollowupsallowed,numberfollowupssent,
469                         dateprinted,sourced,quantityreceiveddamaged,
470                         subscriptionfrom,subscriptionto
471                         "
472         );
473 # the other hash contains other actions that can't be done elsewhere. they are done
474 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
475
476 # The tabledata hash contains data that should be in the tables.
477 # The uniquefieldrequired hash entry is used to determine which (if any) fields
478 # must not exist in the table for this row to be inserted.  If the
479 # uniquefieldrequired entry is already in the table, the existing data is not
480 # modified, unless the forceupdate hash entry is also set.  Fields in the
481 # anonymous "forceupdate" hash will be forced to be updated to the default
482 # values given in the %tabledata hash.
483
484 my %tabledata = (
485     userflags => [
486         {
487             uniquefieldrequired => 'bit',
488             bit                 => 0,
489             flag                => 'superlibrarian',
490             flagdesc            => 'Access to all librarian functions',
491             defaulton           => 0
492         },
493         {
494             uniquefieldrequired => 'bit',
495             bit                 => 1,
496             flag                => 'circulate',
497             flagdesc            => 'Circulate books',
498             defaulton           => 0
499         },
500         {
501             uniquefieldrequired => 'bit',
502             bit                 => 2,
503             flag                => 'catalogue',
504             flagdesc            => 'View Catalogue (Librarian Interface)',
505             defaulton           => 0
506         },
507         {
508             uniquefieldrequired => 'bit',
509             bit                 => 3,
510             flag                => 'parameters',
511             flagdesc            => 'Set Koha system paramters',
512             defaulton           => 0
513         },
514         {
515             uniquefieldrequired => 'bit',
516             bit                 => 4,
517             flag                => 'borrowers',
518             flagdesc            => 'Add or modify borrowers',
519             defaulton           => 0
520         },
521         {
522             uniquefieldrequired => 'bit',
523             bit                 => 5,
524             flag                => 'permissions',
525             flagdesc            => 'Set user permissions',
526             defaulton           => 0
527         },
528         {
529             uniquefieldrequired => 'bit',
530             bit                 => 6,
531             flag                => 'reserveforothers',
532             flagdesc            => 'Reserve books for patrons',
533             defaulton           => 0
534         },
535         {
536             uniquefieldrequired => 'bit',
537             bit                 => 7,
538             flag                => 'borrow',
539             flagdesc            => 'Borrow books',
540             defaulton           => 1
541         },
542         {
543             uniquefieldrequired => 'bit',
544             bit                 => 8,
545             flag                => 'reserveforself',
546             flagdesc            => 'Reserve books for self',
547             defaulton           => 0
548         },
549         {
550             uniquefieldrequired => 'bit',
551             bit                 => 9,
552             flag                => 'editcatalogue',
553             flagdesc  => 'Edit Catalogue (Modify bibliographic/holdings data)',
554             defaulton => 0
555         },
556         {
557             uniquefieldrequired => 'bit',
558             bit                 => 10,
559             flag                => 'updatecharges',
560             flagdesc            => 'Update borrower charges',
561             defaulton           => 0
562         },
563         {
564             uniquefieldrequired => 'bit',
565             bit                 => 11,
566             flag                => 'acquisition',
567             flagdesc            => 'Acquisition and/or suggestion management',
568             defaulton           => 0
569         },
570         {
571             uniquefieldrequired => 'bit',
572             bit                 => 12,
573             flag                => 'management',
574             flagdesc            => 'Set library management parameters',
575             defaulton           => 0
576         },
577         {
578             uniquefieldrequired => 'bit',
579             bit                 => 13,
580             flag                => 'tools',
581             flagdesc            => 'Use tools (export, import, barcodes)',
582             defaulton           => 0
583         },        
584     ],
585     systempreferences => [
586         {
587             uniquefieldrequired => 'variable',
588             forceupdate         => { 'explanation' => 1,
589                                      'type' => 1 },
590             variable            => 'LibraryName',
591             value               => '<i><b>Koha<br/>Free Software ILS<br/><br/></b>Koha : a gift, a contribution<br/> in Maori</i>',
592             explanation         => 'Library name as shown on main opac page',
593             type                => ''
594
595         },
596         {
597             uniquefieldrequired => 'variable',
598             forceupdate         => { 'explanation' => 1,
599                                      'type' => 1 },
600             variable            => 'autoMemberNum',
601             value               => '1',
602             explanation         => 'Member number is auto-calculated',
603             type                => 'YesNo'
604
605         },
606         {
607             uniquefieldrequired => 'variable',
608             forceupdate         => { 'explanation' => 1,
609                                      'type' => 1,
610                                      'options' => 1 },
611             variable            => 'acquisitions',
612             value               => 'normal',
613             explanation         =>
614 'Normal, budget-based acquisitions, or Simple bibliographic-data acquisitions',
615             type                => 'Choice',
616             options             => 'simple|normal'
617         },
618         {
619             uniquefieldrequired => 'variable',
620             forceupdate         => { 'explanation' => 1,
621                                      'type' => 1,
622                                      'options' => 1 },
623             variable            => 'dateformat',
624             value               => 'metric',
625             explanation         =>
626             'date format (us mm/dd/yyyy, metric dd/mm/yyy, ISO yyyy/mm/dd)',
627             type                => 'Choice',
628             options             => 'metric|us|iso'
629         },
630         {
631             uniquefieldrequired => 'variable',
632             variable            => 'template',
633             forceupdate         => { 'explanation' => 1,
634                                      'type' => 1 },
635             value               => 'default',
636             explanation         => 'Preference order for intranet interface templates',
637             type                => 'Themes'
638         },
639         {
640             uniquefieldrequired => 'variable',
641             variable            => 'autoBarcode',
642             forceupdate         => { 'explanation' => 1,
643                                      'type' => 1 },
644             value               => 'yes',
645             explanation         => 'Barcode is auto-calculated',
646             type                => 'YesNo'
647         },
648         {
649             uniquefieldrequired => 'variable',
650             variable            => 'insecure',
651             forceupdate         => { 'explanation' => 1,
652                                      'type' => 1 },
653             value               => 'no',
654             explanation         =>
655 'If YES, no auth at all is needed. Be careful if you set this to yes!',
656             type                => 'YesNo'
657         },
658         {
659             uniquefieldrequired => 'variable',
660             variable            => 'authoritysep',
661             forceupdate         => { 'explanation' => 1,
662                                      'type' => 1,
663                                      'options' => 1 },
664             value               => '--',
665             explanation         =>
666             'the separator used in authority/thesaurus. Usually --',
667             type                => 'free',
668             options             => '10'
669         },
670         {
671             uniquefieldrequired => 'variable',
672             variable            => 'opaclanguages',
673             forceupdate         => { 'explanation' => 1,
674                                      'type' => 1 },
675             value               => 'en',
676             explanation         => 'Set the preferred order for translations.  The top language will be tried first.',
677             type                => 'Languages'
678         },
679         {
680             uniquefieldrequired => 'variable',
681             variable            => 'opacthemes',
682             forceupdate         => { 'explanation' => 1,
683                                      'type' => 1 },
684             value               => 'css',
685             explanation         => 'Set the preferred order for themes.  The top theme will be tried first.',
686             type                => 'Themes'
687         },
688         {
689             uniquefieldrequired => 'variable',
690             variable            => 'timeout',
691             forceupdate         => { 'explanation' => 1,
692                                      'type' => 1 },
693             value               => '1200',
694             explanation         => 'Inactivity timeout for cookies authentication (in seconds)',
695             type                => 'Integer'
696         },
697         {
698             uniquefieldrequired => 'variable',
699             variable            => 'marc',
700             forceupdate         => { 'explanation' => 1,
701                                      'type' => 1 },
702             value               => 'yes',
703             explanation         => 'Turn on MARC support',
704             type                => 'YesNo'
705         },
706         {
707             uniquefieldrequired => 'variable',
708             variable            => 'marcflavour',
709             forceupdate         => { 'explanation' => 1,
710                                      'type' => 1,
711                                      'options' => 1},
712             value               => 'MARC21',
713             explanation         =>
714             'your MARC flavor (MARC21 or UNIMARC) used for character encoding',
715             type                => 'Choice',
716             options             => 'MARC21|UNIMARC'
717         },
718         {
719             uniquefieldrequired => 'variable',
720             variable            => 'checkdigit',
721             value               => 'none',
722             forceupdate         => { 'explanation' => 1,
723                                      'type' => 1,
724                                      'options' => 1},
725             explanation         => 'Validity checks on membership number: none or "Katipo" style checks',
726             type                => 'Choice',
727             options             => 'none|katipo'
728         },
729         {
730             uniquefieldrequired => 'variable',
731             variable            => 'maxoutstanding',
732             forceupdate         => { 'explanation' => 1,
733                                      'type' => 1 },
734             value               => '5',
735             explanation         =>
736             'maximum amount withstanding to be able make reserves ',
737             type                => 'Integer'
738         },
739         {
740             uniquefieldrequired => 'variable',
741             variable            => 'maxreserves',
742             forceupdate         => { 'explanation' => 1,
743                                      'type' => 1 },
744             value               => '5',
745             explanation         =>
746             'maximum number of reserves a member can make',
747             type                => 'Integer'
748
749         },
750         {
751             uniquefieldrequired => 'variable',
752             variable            => 'noissuescharge',
753             forceupdate         => { 'explanation' => 1,
754                                      'type' => 1 },
755             value               => '5',
756             explanation         =>
757             'maximum amount withstanding to be able to check out an item',
758             type                => 'Integer'
759
760         },
761         {
762             uniquefieldrequired => 'variable',
763             variable            => 'KohaAdminEmailAddress',
764             forceupdate         => { 'explanation' => 1,
765                                      'type' => 1 },
766             value               => 'your.mail@here',
767             explanation => 'the email address where borrowers modifs are sent',
768             type                => 'free'
769         },
770         {
771             uniquefieldrequired => 'variable',
772             variable            => 'gist',
773             forceupdate         => { 'explanation' => 1,
774                                      'type' => 1 },
775             value               => '0.125',
776             explanation => 'the gist rate. NOT in %, but in numeric form (0.12 for 12%)',
777             type                => 'free'
778         },
779         {
780             uniquefieldrequired => 'variable',
781             variable            => 'printcirculationslips',
782             forceupdate         => { 'explanation' => 1,
783                                      'type' => 1 },
784             value               => '0',
785             explanation => 'if set to 1, print circulation slips. If set to 0, don\'t',
786             type                => 'free'
787         },
788         {
789             uniquefieldrequired => 'variable',
790             variable            => 'suggestion',
791             forceupdate         => { 'explanation' => 1,
792                                      'type' => 1 },
793             value               => '0',
794             explanation => 'if set to 1, suggestions are activated in OPAC',
795             type                => 'free'
796         },
797         {
798             uniquefieldrequired => 'variable',
799             variable            => 'ISBD',
800             forceupdate         => { 'explanation' => 1,
801                                      'type' => 1 },
802             value               => 'Fill with appropriate value...',
803             explanation => 'ISBD',
804             type                => 'free'
805         },
806         {
807             uniquefieldrequired => 'variable',
808             variable            => 'virtualshelves',
809             forceupdate         => { 'explanation' => 1,
810                                      'type' => 1 },
811             value               => '0',
812             explanation => 'Set virtual shelves management ON or OFF',
813             type                => 'YesNo'
814         },
815         {
816             uniquefieldrequired => 'variable',
817             variable            => 'itemcallnumber',
818             forceupdate         => { 'explanation' => 1,
819                                      'type' => 1 },
820             value               => '676a',
821             explanation => 'The MARC field/subfield that is used to calculate the itemcallnumber (in UNIMARC : 676a for Dewey, 680a for Loc)',
822             type                => 'free'
823         },
824         {
825             uniquefieldrequired => 'variable',
826             variable            => 'BiblioDefaultView',
827             value               => 'normal',
828             forceupdate         => { 'explanation' => 1,
829                                      'type' => 1,
830                                      'options' => 1},
831             explanation         => 'Define the default view of a biblio. Can be either normal, marc or isbd',
832             type                => 'Choice',
833             options             => 'normal|marc|isbd'
834         },
835         {
836             uniquefieldrequired => 'variable',
837             variable            => 'opacstylesheet',
838             value               => '',
839             forceupdate         => { 'explanation' => 1,
840                                      'type' => 1},
841             explanation         => 'Enter a complete URL to use an alternate stylesheet in OPAC',
842             type                => 'free',
843         },
844         {
845             uniquefieldrequired => 'variable',
846             variable            => 'opacsmallimage',
847             value               => '',
848             forceupdate         => { 'explanation' => 1,
849                                      'type' => 1},
850             explanation         => 'Enter a complete URL to an image, will be on top/left instead of the Koha logo',
851             type                => 'free',
852         },
853         {
854             uniquefieldrequired => 'variable',
855             variable            => 'opaclargeimage',
856             value               => '',
857             forceupdate         => { 'explanation' => 1,
858                                      'type' => 1},
859             explanation         => 'Enter a complete URL to an image, will be on the main page, instead of the Koha logo',
860             type                => 'free',
861         },
862         {
863             uniquefieldrequired => 'variable',
864             variable            => 'delimiter',
865             value               => ';',
866             forceupdate         => { 'explanation' => 1,
867                                      'type' => 1},
868             explanation         => 'separator for reports exported to spreadsheet',
869             type                => 'free',
870         },
871         {
872             uniquefieldrequired => 'variable',
873             variable            => 'MIME',
874             value               => 'OPENOFFICE.ORG',
875             forceupdate         => { 'explanation' => 1,
876                                      'type' => 1,
877                                      'options' => 1},
878             explanation         => 'Define the default application for report exportations into files',
879                 type            => 'Choice',
880                 options         => 'EXCEL|OPENOFFICE.ORG'
881         },
882         {
883             uniquefieldrequired => 'variable',
884             variable            => 'Delimiter',
885             value               => ';',
886                 forceupdate             => { 'explanation' => 1,
887                                      'type' => 1,
888                                      'options' => 1},
889             explanation         => 'Define the default separator character for report exportations into files',
890                 type            => 'Choice',
891                 options         => ';|tabulation|,|/|\|#'
892         },
893         {
894             uniquefieldrequired => 'variable',
895             variable            => 'SubscriptionHistory',
896             value               => ';',
897                 forceupdate             => { 'explanation' => 1,
898                                      'type' => 1,
899                                      'options' => 1},
900             explanation         => 'Define the information level for serials history in OPAC',
901                 type            => 'Choice',
902                 options         => 'simplified|full'
903         },
904         {
905             uniquefieldrequired => 'variable',
906             variable            => 'hidelostitems',
907             value               => 'No',
908             forceupdate         => { 'explanation' => 1,
909                                      'type' => 1},
910             explanation         => 'show or hide "lost" items in OPAC.',
911             type                => 'YesNo',
912         },
913         {
914             uniquefieldrequired => 'variable',
915             variable            => 'Activate_Log',
916             value               => 'On',
917             forceupdate         => { 'explanation' => 1,
918                                      'type' => 1},
919             explanation         => 'Turn Log Actions on DB On an Off',
920             type                => 'YesNo',
921         },
922     ],
923
924 );
925
926 my %fielddefinitions = (
927     printers => [
928         {
929             field   => 'printername',
930             type    => 'char(40)',
931             null    => '',
932             key     => 'PRI',
933             default => ''
934         },
935     ],
936     aqbookfund => [
937         {
938             field   => 'bookfundid',
939             type    => 'char(5)',
940             null    => '',
941             key     => 'PRI',
942             default => ''
943         },
944         {
945             field   => 'branchcode',
946             type    => 'varchar(4)',
947             null    => 'NULL',
948             key     => '',
949             default =>'',
950             extra => ''
951         },
952     ],
953     aqbudget => [
954         {
955             field   => 'aqbudgetid',
956             type    => 'tinyint(4)',
957             null    => '',
958             key     => 'PRI',
959                   default =>'',
960             extra => 'auto_increment'
961         },
962         {
963             field   => 'branchcode',
964             type    => 'varchar(4)',
965             null    => 'NULL',
966             key     => '',
967             default =>'',
968             extra => ''
969         },
970     ],
971     z3950servers => [
972         {
973             field   => 'id',
974             type    => 'int',
975             null    => '',
976             key     => 'PRI',
977             default => '',
978             extra   => 'auto_increment'
979         },
980     ],
981         marc_breeding => [
982         {
983             field   => 'z3950random',
984             type    => 'varchar(40)',
985             null    => 'NULL',
986             key     => '',
987             default => '',
988             extra   => ''
989         },
990         {
991             field   => 'encoding',
992             type    => 'varchar(40)',
993             null    => '',
994             key     => '',
995             default => '',
996             extra   => ''
997         },
998     ],
999 );
1000
1001 #-------------------
1002 # Initialize
1003
1004 # Start checking
1005
1006 # Get version of MySQL database engine.
1007 my $mysqlversion = `mysqld --version`;
1008 $mysqlversion =~ /Ver (\S*) /;
1009 $mysqlversion = $1;
1010 if ( $mysqlversion ge '3.23' ) {
1011     print "Could convert to MyISAM database tables...\n" unless $silent;
1012 }
1013
1014 #---------------------------------
1015 # Tables
1016
1017 # Collect all tables into a list
1018 $sth = $dbh->prepare("show tables");
1019 $sth->execute;
1020 while ( my ($table) = $sth->fetchrow ) {
1021     $existingtables{$table} = 1;
1022 }
1023
1024
1025 # Now add any missing tables
1026 foreach $table ( keys %requiretables ) {
1027     unless ( $existingtables{$table} ) {
1028         print "Adding $table table...\n" unless $silent;
1029         my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1030         $sth->execute;
1031         if ( $sth->err ) {
1032             print "Error : $sth->errstr \n";
1033             $sth->finish;
1034         }    # if error
1035     }    # unless exists
1036 }    # foreach
1037
1038 # now drop useless tables
1039 foreach $table ( keys %dropable_table ) {
1040         if ( $existingtables{$table} ) {
1041                 print "Dropping unused table $table\n" if $debug and not $silent;
1042                 $dbh->do("drop table $table");
1043                 if ( $dbh->err ) {
1044                         print "Error : $dbh->errstr \n";
1045                 }
1046         }
1047 }
1048 unless ( $existingtables{'z3950servers'} ) {
1049         #MJR: added syntax entries to close bug 624
1050     print "Adding z3950servers table...\n" unless $silent;
1051     my $sti = $dbh->prepare( "create table z3950servers (
1052                                                                                 host char(255),
1053                                                                                 port int,
1054                                                                                 db char(255),
1055                                                                                 userid char(255),
1056                                                                                 password char(255),
1057                                                                                 name text,
1058                                                                                 id int,
1059                                                                                 checked smallint,
1060                                                                                 rank int,
1061                                                                                 syntax char(80))"
1062     );
1063     $sti->execute;
1064     $sti = $dbh->prepare( "insert into z3950servers
1065                                                                 values ('z3950.loc.gov',
1066                                                                 7090,
1067                                                                 'voyager',
1068                                                                 '', '',
1069                                                                 'Library of Congress',
1070                                                                 1, 1, 1, 'USMARC')"
1071     );
1072     $sti->execute;
1073 }
1074 unless ( $existingtables{'issuingrules'} ) {
1075         $dbh->do("alter table categoryitem rename issuingrules");
1076         $dbh->do("ALTER TABLE issuingrules ADD maxissueqty int(4) default NULL");
1077         $dbh->do("ALTER TABLE issuingrules ADD issuelength int(4) default NULL");
1078         $dbh->do("ALTER TABLE issuingrules ADD branchcode varchar(4) NOT NULL default ''");
1079         print "renaming categoryitem\n" unless $silent;
1080 }
1081
1082
1083 #---------------------------------
1084 # Columns
1085
1086 foreach $table ( keys %requirefields ) {
1087     print "Check table $table\n" if $debug and not $silent;
1088     $sth = $dbh->prepare("show columns from $table");
1089     $sth->execute();
1090     undef %types;
1091     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1092     {
1093         $types{$column} = $type;
1094     }    # while
1095     foreach $column ( keys %{ $requirefields{$table} } ) {
1096         print "  Check column $column  [$types{$column}]\n" if $debug and not $silent;
1097         if ( !$types{$column} ) {
1098
1099             # column doesn't exist
1100             print "Adding $column field to $table table...\n" unless $silent;
1101             $query = "alter table $table
1102                         add column $column " . $requirefields{$table}->{$column};
1103             print "Execute: $query\n" if $debug;
1104             my $sti = $dbh->prepare($query);
1105             $sti->execute;
1106             if ( $sti->err ) {
1107                 print "**Error : $sti->errstr \n";
1108                 $sti->finish;
1109             }    # if error
1110         }    # if column
1111     }    # foreach column
1112 }    # foreach table
1113
1114 foreach $table ( keys %fielddefinitions ) {
1115         print "Check table $table\n" if $debug;
1116         $sth = $dbh->prepare("show columns from $table");
1117         $sth->execute();
1118         my $definitions;
1119         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1120         {
1121                 $definitions->{$column}->{type}    = $type;
1122                 $definitions->{$column}->{null}    = $null;
1123                 $definitions->{$column}->{key}     = $key;
1124                 $definitions->{$column}->{default} = $default;
1125                 $definitions->{$column}->{extra}   = $extra;
1126         }    # while
1127         my $fieldrow = $fielddefinitions{$table};
1128         foreach my $row (@$fieldrow) {
1129                 my $field   = $row->{field};
1130                 my $type    = $row->{type};
1131                 my $null    = $row->{null};
1132                 my $key     = $row->{key};
1133                 my $default = $row->{default};
1134                 $default="''" unless $default;
1135                 my $extra   = $row->{extra};
1136                 my $def     = $definitions->{$field};
1137                 unless ( $type eq $def->{type}
1138                         && $null eq $def->{null}
1139                         && $key eq $def->{key}
1140                         && $default eq $def->{default}
1141                         && $extra eq $def->{extra} )
1142                 {
1143
1144                         if ( $null eq '' ) {
1145                                 $null = 'NOT NULL';
1146                         }
1147                         if ( $key eq 'PRI' ) {
1148                                 $key = 'PRIMARY KEY';
1149                         }
1150                         unless ( $extra eq 'auto_increment' ) {
1151                                 $extra = '';
1152                         }
1153                         # if it's a new column use "add", if it's an old one, use "change".
1154                         my $action;
1155                         if ($definitions->{$field}->{type}) {
1156                                 $action="change $field"
1157                         } else {
1158                                 $action="add";
1159                         }
1160 # if it's a primary key, drop the previous pk, before altering the table
1161                         my $sth;
1162                         if ($key ne 'PRIMARY KEY') {
1163                                 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
1164                         } else {
1165                                 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
1166                         }
1167                         $sth->execute($default);
1168                         print "  Alter $field in $table\n" unless $silent;
1169                 }
1170         }
1171 }
1172
1173 # Get list of columns from borrowers table
1174 my %itemtypes;
1175 my %nullenabled;
1176 $sth = $dbh->prepare("show columns from borrowers");
1177 $sth->execute;
1178 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1179 {
1180     $itemtypes{$column} = $type;
1181     $nullenabled{$column} = $null;
1182 }
1183
1184 unless ( $itemtypes{'cardnumber'} eq 'varchar(20)' ) {
1185     $itemtypes{'cardnumber'} =~ /varchar\((\d+)\)/;
1186     my $oldlength = $1;
1187     if ( $oldlength < 16 ) {
1188         print "Setting maximum cardnumber length to 16 (was $oldlength) and marking unique.\n" unless $silent;
1189         my $sti =
1190           $dbh->prepare(
1191             "alter table borrowers change cardnumber cardnumber varchar(16)");
1192         $sti->execute;
1193         $sti->finish;
1194         $sti =
1195           $dbh->prepare(
1196             "alter table borrowers drop index cardnumber");
1197         $sti->execute;
1198         $sti->finish;
1199         $sti =
1200           $dbh->prepare(
1201             "alter table borrowers add unique(cardnumber)");
1202         $sti->execute;
1203         $sti->finish;
1204     }
1205 }
1206 #
1207 # Get list of columns from items table
1208 $sth = $dbh->prepare("show columns from items");
1209 $sth->execute;
1210 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1211 {
1212     $itemtypes{$column} = $type;
1213     $nullenabled{$column} = $null;
1214 }
1215
1216 unless ( $itemtypes{'barcode'} eq 'varchar(20)' ) {
1217     $itemtypes{'barcode'} =~ /varchar\((\d+)\)/;
1218     my $oldlength = $1;
1219     if ( $oldlength < 20 ) {
1220         print "Setting maximum barcode length to 20 (was $oldlength).\n" unless $silent;
1221         my $sti =
1222           $dbh->prepare(
1223             "alter table items change barcode barcode varchar(20)");
1224         $sti->execute;
1225     }
1226 }
1227 #
1228 # dropping unique barcode index & setting barcode to null allowed.
1229 #
1230 $sth = $dbh->prepare("show index from items");
1231 $sth->execute;
1232 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1233 {
1234         if ($key_name eq 'barcode' && $non_unique eq 0) {
1235                 print "dropping BARCODE index to enable empty barcodes\n" unless $silent;
1236                 $dbh->do("ALTER TABLE `items` DROP INDEX `barcode`");
1237         }
1238 }
1239 $dbh->do("ALTER TABLE `items` CHANGE `barcode` `barcode` VARCHAR( 20 )") unless ($nullenabled{barcode} eq 'YES');
1240
1241 #
1242 # creating fulltext index in bibliothesaurus if needed
1243 #
1244 $sth = $dbh->prepare("show index from bibliothesaurus");
1245 $sth->execute;
1246 my $exists=0;
1247 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1248 {
1249         if ($key_name eq 'category_2') {
1250                 $exists=1;
1251         }
1252 }
1253 print "Creating fulltext index on bibliothesaurus\n" unless $exists or $silent;
1254 $dbh->do('create fulltext index category_2 on bibliothesaurus (category,freelib)') unless $exists;
1255
1256 #
1257 # creating  index in z3950results if needed
1258 #
1259 $sth = $dbh->prepare("show index from z3950results");
1260 $sth->execute;
1261 my $exists=0;
1262 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1263 {
1264         if ($key_name eq 'query_server') {
1265                 $exists=1;
1266         }
1267 }
1268 print "Creating  index on z3950results\n" unless $exists or $silent;
1269 $dbh->do('create unique index query_server on z3950results (queryid,server)') unless $exists;
1270
1271 # changing z3950daemon field to NULL in marc_breeding
1272 $dbh->do("ALTER TABLE `marc_breeding` CHANGE `z3950random` `z3950random` VARCHAR( 40 )");
1273
1274 # making borrowernumber an auto_increment field
1275 $dbh->do("ALTER TABLE `borrowers` CHANGE `borrowernumber` `borrowernumber` INTEGER auto_increment");
1276
1277 # changing indexes in marc_*_structure to use frameworkcode
1278 $dbh->do('alter table marc_subfield_structure drop index tab');
1279 $dbh->do('create index tab on marc_subfield_structure (frameworkcode,tab)');
1280 $dbh->do('alter table marc_subfield_structure drop index kohafield');
1281 $dbh->do('create index kohafield on marc_subfield_structure (frameworkcode,kohafield)');
1282
1283
1284 # extending the timestamp in branchtransfers...
1285 my %branchtransfers;
1286
1287 $sth = $dbh->prepare("show columns from branchtransfers");
1288 $sth->execute;
1289 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1290 {
1291     $branchtransfers{$column} = $type;
1292 }
1293
1294 unless ( $branchtransfers{'datesent'} eq 'datetime' ) {
1295     print "Setting type of datesent in branchtransfers to datetime.\n" unless $silent;
1296     my $sti =
1297       $dbh->prepare(
1298         "alter table branchtransfers change datesent datesent datetime");
1299     $sti->execute;
1300 }
1301
1302 unless ( $branchtransfers{'datearrived'} eq 'datetime' ) {
1303     print "Setting type of datearrived in branchtransfers to datetime.\n" unless $silent;
1304     my $sti =
1305       $dbh->prepare(
1306         "alter table branchtransfers change datearrived datearrived datetime");
1307     $sti->execute;
1308 }
1309
1310 # changing the branchcategories table around...
1311 my %branchcategories;
1312
1313 $sth = $dbh->prepare("show columns from branchcategories");
1314 $sth->execute;
1315 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1316 {
1317     $branchcategories{$column} = $type;
1318 }
1319
1320 unless ( $branchcategories{'categorycode'} eq 'varchar(4)' ) {
1321     print
1322 "Setting type of categorycode in branchcategories to varchar(4),\n and making the primary key.\n" unless $silent;
1323     my $sti =
1324       $dbh->prepare(
1325 "alter table branchcategories change categorycode categorycode varchar(4) not null"
1326     );
1327     $sti->execute;
1328     $sti =
1329       $dbh->prepare(
1330         "alter table branchcategories add primary key (categorycode)");
1331     $sti->execute;
1332 }
1333
1334 unless ( $branchcategories{'categoryname'} eq 'text' ) {
1335     print "Changing branchcode in branchcategories to categoryname text.\n" unless $silent;
1336     my $sth =
1337       $dbh->prepare(
1338         "alter table branchcategories change branchcode categoryname text");
1339     $sth->execute;
1340 }
1341
1342 unless ( $branchcategories{'codedescription'} eq 'text' ) {
1343     print
1344 "Replacing branchholding in branchcategories with codedescription text.\n" unless $silent;
1345     my $sth =
1346       $dbh->prepare(
1347         "alter table branchcategories change branchholding codedescription text"
1348     );
1349     $sth->execute;
1350 }
1351
1352 # changing the items table around...
1353 my %items;
1354
1355 $sth = $dbh->prepare("show columns from items");
1356 $sth->execute;
1357 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1358 {
1359     $items{$column} = $type;
1360 }
1361
1362 if ($items{'bulk'} eq "varchar(30)") {
1363     print "  Setting callnumber in items table\n" unless $silent;
1364     my $sti =
1365       $dbh->prepare("ALTER TABLE `items` CHANGE `bulk` `itemcallnumber` VARCHAR( 30 ) DEFAULT NULL");
1366     $sti->execute;
1367     $sti = $dbh->prepare("update marc_subfield_structure set kohafield=\"items.itemcallnumber\" where kohafield=\"items.bulk\"");
1368     $sti->execute;
1369 }
1370
1371 # changing the marc_subfield_structure table around...
1372 my %marc_subfield_structure;
1373
1374 $sth = $dbh->prepare("show columns from marc_subfield_structure");
1375 $sth->execute;
1376 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1377 {
1378     $marc_subfield_structure{$column} = $type;
1379 }
1380
1381 if ($marc_subfield_structure{thesaurus_category}) {
1382     print "  changing thesaurus_category in marc_subfield_structure table\n" unless $silent;
1383     my $sti =
1384       $dbh->prepare("ALTER TABLE marc_subfield_structure CHANGE `thesaurus_category` `authtypecode` VARCHAR(10 ) DEFAULT NULL");
1385     $sti->execute;
1386 }
1387
1388 #
1389 # creating  index in issuingrules if needed
1390 #
1391 $sth = $dbh->prepare("show index from issuingrules");
1392 $sth->execute;
1393 my $exists=0;
1394 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1395 {
1396         if ($key_name eq 'PRIMARY') {
1397                 $exists=1;
1398         }
1399 }
1400 print "Creating  index on issuing rules\n" unless $exists or $silent;
1401 $dbh->do('ALTER TABLE issuingrules ADD PRIMARY KEY ( branchcode, categorycode, itemtype )') unless $exists;
1402
1403 $dbh->do('ALTER TABLE marc_tag_structure drop primary key');
1404 $dbh->do('ALTER TABLE marc_tag_structure ADD PRIMARY KEY ( frameworkcode, tagfield )');
1405
1406 $dbh->do('ALTER TABLE marc_subfield_structure drop primary key');
1407 $dbh->do('ALTER TABLE marc_subfield_structure ADD PRIMARY KEY ( frameworkcode, tagfield, tagsubfield )');
1408
1409 # Get list of columns from marc_word table
1410 my %marc_word;
1411 my %nullenabled;
1412 $sth = $dbh->prepare("show columns from marc_word");
1413 $sth->execute;
1414 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1415 {
1416     $marc_word{$column} = $type;
1417     $nullenabled{$column} = $null;
1418 }
1419 if ($marc_word{subfieldid}) {
1420         #create field tagsubfield, copy tag+subfieldid, then drop tag and subfieldid
1421         print "Modifying marc_word (concat on tag and subfield for better perfs)\n" unless $silent;
1422         $dbh->do("ALTER TABLE `marc_word` ADD `tagsubfield` CHAR( 4 ) NOT NULL AFTER `bibid`");
1423         $dbh->do("update marc_word set tagsubfield=concat(tag,subfieldid)");
1424         $dbh->do("alter table marc_word drop tag");
1425         $dbh->do("alter table marc_word drop subfieldid");
1426         $dbh->do("create index Search_Marc on marc_word (tagsubfield,word)");
1427 }
1428 # Populate tables with required data
1429
1430 # fill aqbasket if it's empty and aqorder is not
1431 # => it means it has just been created & must be filled
1432 $sth = $dbh->prepare("select count(*) from aqbasket");
1433 $sth->execute;
1434 if ($sth->fetchrow == 0) {
1435         $sth = $dbh->prepare("select count(*) from aqorders");
1436         $sth->execute;
1437         if ($sth->fetchrow >0) {
1438                 print "Populating new table aqbasket\n";
1439                 print "IMPORTANT NOTE: error message \"Duplicate entry 'X' for key 1\" may appear. it should not be a real trouble\n";
1440                 $sth=$dbh->prepare("select distinct basketno,booksellerid,authorisedby,entrydate,booksellerinvoicenumber from aqorders");
1441                 $sth->execute;
1442                 my ($basketno,$booksellerid,$authorisedby,$entrydate,$booksellerinvoicenumber);
1443                 my $sth2 = $dbh->prepare("insert into aqbasket (basketno,creationdate,booksellerid,authorisedby,booksellerinvoicenumber) values (?,?,?,?,?)");
1444                 while (($basketno,$booksellerid,$authorisedby,$entrydate,$booksellerinvoicenumber) = $sth->fetchrow) {
1445                         print "$basketno,$entrydate,$booksellerid,$authorisedby,$booksellerinvoicenumber\n";
1446                         $sth2->execute($basketno,$entrydate,$booksellerid,$authorisedby,$booksellerinvoicenumber);
1447                 }
1448         }
1449 }
1450 foreach my $table ( keys %tabledata ) {
1451     print "Checking for data required in table $table...\n" unless $silent;
1452     my $tablerows = $tabledata{$table};
1453     foreach my $row (@$tablerows) {
1454         my $uniquefieldrequired = $row->{uniquefieldrequired};
1455         my $uniquevalue         = $row->{$uniquefieldrequired};
1456         my $forceupdate         = $row->{forceupdate};
1457         my $sth                 =
1458           $dbh->prepare(
1459 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1460         );
1461         $sth->execute($uniquevalue);
1462         if ($sth->rows) {
1463             foreach my $field (keys %$forceupdate) {
1464                 if ($forceupdate->{$field}) {
1465                     my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1466                     $sth->execute($row->{$field}, $uniquevalue);
1467                 }
1468             }
1469         } else {
1470             print "Adding row to $table: " unless $silent;
1471             my @values;
1472             my $fieldlist;
1473             my $placeholders;
1474             foreach my $field ( keys %$row ) {
1475                 next if $field eq 'uniquefieldrequired';
1476                 next if $field eq 'forceupdate';
1477                 my $value = $row->{$field};
1478                 push @values, $value;
1479                 print "  $field => $value" unless $silent;
1480                 $fieldlist .= "$field,";
1481                 $placeholders .= "?,";
1482             }
1483             print "\n" unless $silent;
1484             $fieldlist    =~ s/,$//;
1485             $placeholders =~ s/,$//;
1486             my $sth =
1487               $dbh->prepare(
1488                 "insert into $table ($fieldlist) values ($placeholders)");
1489             $sth->execute(@values);
1490         }
1491     }
1492 }
1493
1494 # at last, remove useless fields
1495 foreach $table ( keys %uselessfields ) {
1496         my @fields = split /,/,$uselessfields{$table};
1497         my $fields;
1498         my $exists;
1499         foreach my $fieldtodrop (@fields) {
1500                 $fieldtodrop =~ s/\t//g;
1501                 $fieldtodrop =~ s/\n//g;
1502                 $exists =0;
1503                 $sth = $dbh->prepare("show columns from $table");
1504                 $sth->execute;
1505                 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1506                 {
1507                         $exists =1 if ($column eq $fieldtodrop);
1508                 }
1509                 if ($exists) {
1510                         print "deleting $fieldtodrop field in $table...\n" unless $silent;
1511                         my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
1512                         $sth->execute;
1513                 }
1514         }
1515 }    # foreach
1516
1517
1518 $sth->finish;
1519
1520 exit;
1521
1522 # $Log$
1523 # Revision 1.109  2005/07/19 16:48:16  hdl
1524 # Adding an object field to action_logs.
1525 # + Minor Correction to updatedatabase
1526 # Changing Activate_Log from choice to YesNo Variable.
1527 #
1528 # Revision 1.108  2005/07/15 16:10:35  hdl
1529 # Adding Log Facility.
1530 # Needs Two Update in database...
1531 # On more table (action_logs)
1532 # And One more syspref Activate_Log, with On|Off values.
1533 # Maintainance has been sweeped of previous Log functions
1534 # addbiblio.pl contains a sample of code using Log.pm
1535 # To be generalized to Authorities, acquisitions, members soon.
1536 #
1537 # Revision 1.107  2005/07/14 09:53:10  hdl
1538 # Adding a log facility for actions watching.
1539 # Code to be widely used in order to report data modifications.
1540 #
1541 # Revision 1.106  2005/07/06 17:47:22  hdl
1542 # Add branch selection and filter for budgets and funds.
1543 # May be too much... Funds could be enough....
1544 #
1545 # It works provided you update your base adding branchcode both in aqbookfund AND aqbudget.
1546 # If selection in budget is not needed, I shall remove.
1547 #
1548 # Revision 1.105  2005/06/20 14:36:44  tipaul
1549 # synch'ing 2.2 and head
1550 #
1551 # Revision 1.100.2.5  2005/06/06 15:23:36  tipaul
1552 # adding a systempref to choose either to show or hide "lost" items. Note that "lost items" can be related to an authorised value list, so does not necessary mean "item definetly lost". Even here, some libraries want to see lost items, and some don't want. This parameter will make everybody happy !
1553 #
1554 # Revision 1.100.2.4  2005/06/06 14:15:55  tipaul
1555 # adding 2 systemparameters to define an alternate image as logo in opac (the image on main page & on each top-left page)
1556 #
1557 # Revision 1.100.2.3  2005/06/02 21:05:34  hdl
1558 # adding variable SubscriptionHistory
1559 #
1560 # Revision 1.100.2.2  2005/03/29 15:41:43  tipaul
1561 # * new permissions : management & tools. You now have 2 new permissions :
1562 #       - management : means the user can manage library parameters, but NOT system parameters.
1563 #       - parameters : means the user can manage all parameters (including system parameters : marc structure, authorised values, system preferences. Was the only flag previously existing)
1564 #       - tools : means the user can import/export datas & edit barcodes.
1565 # note that for compatibility reasons, a user having "parameters" can access everything.
1566 # * new permission scheme. In every template new variables are available. They are written CAN_user_permission, with permission being one of the permission flag. templates can now show or hidde menu entries depending on user permissions. For example, a user with just circ permissions should have only the "circulation" button on home page. Templates are NOT updated in this version (except for system parameters, as proof of concept), they will be in the next ones. But the scheme is ready.
1567 #
1568 # Revision 1.100.2.1  2005/03/17 17:15:18  tipaul
1569 # defaulting opacstylesheet to '' instead of 'normal' (that is stupid)
1570 #
1571 # Revision 1.100  2004/12/10 16:11:32  tipaul
1572 # Improvement : adding a systempref to define default view in OPAC (either normal, MARC or ISBD). Created automatically during install or update. Check that you have a Koha >> parameters >> systempreferences >> BiblioDefaultView, Variable type : Choice, Variable options : normal|marc|isbd
1573 #
1574 # Revision 1.99  2004/12/02 17:17:00  tipaul
1575 # adding acquisition permission
1576 #
1577 # Revision 1.98  2004/11/26 20:26:49  tipaul
1578 # bugfix for auth_header creation
1579 #
1580 # Revision 1.97  2004/11/23 09:11:08  tipaul
1581 # adding itemcallnumber entry
1582 #
1583 # Revision 1.96  2004/11/16 13:03:45  tipaul
1584 # removing ldap systempref, it's now in C4/Auth_with_ldap.pm separate package
1585 #
1586 # Revision 1.95  2004/11/08 19:57:32  tipaul
1587 # bugfix
1588 #
1589 # Revision 1.94  2004/09/06 10:00:29  tipaul
1590 # adding a "location" field to the library.
1591 # This field is useful when the callnumber contains no information on the room where the item is stored.
1592 # With this field, we now have 3 levels of informations to find a book :
1593 # * the branch.
1594 # * the location.
1595 # * the callnumber.
1596 #
1597 # This should be versatile enough to solve any storing method.
1598 # This hack is quite simple, due to the nice Biblio.pm API. The MARC => koha db link is automatically managed. Just add the link in the parameters section.
1599 #
1600 # Revision 1.93  2004/08/12 14:50:50  tipaul
1601 # bugfixes
1602 #
1603 # Revision 1.92  2004/08/06 16:38:42  tipaul
1604 # changing DB structure to calculate next issue number.
1605 # Seems to work fine.
1606 #
1607 # Still misses the date calculation & the test of end of subscription (maybe for monday ?)
1608 #
1609 # Revision 1.91  2004/07/15 09:52:28  tipaul
1610 # Acquisition & Suggestion :
1611 # * acquisition rewritte : create a aqbasket table to deal with "bookseller order header".
1612 # * add "close basket" feature : a closed basket can't be modified
1613 # * suggestion feature : manage suggestions in acquisition (after suggestion filled in OPAC)
1614 #
1615 # Revision 1.90  2004/07/06 08:24:18  tipaul
1616 # adding 2 free fields that can be used for sorting purposes
1617 #
1618 # Revision 1.89  2004/07/02 15:55:08  tipaul
1619 # Adding 2 new fields, called "sort1" and "sort2"
1620 # They can be used for sorting & statistics reasons by the library.
1621 #
1622 # Revision 1.88  2004/06/26 23:34:26  rangi
1623 # Fixing typo
1624 #
1625 # Revision 1.87  2004/06/23 13:03:09  tipaul
1626 # fixes in DB structure
1627 #
1628 # Revision 1.86  2004/06/22 11:30:57  tipaul
1629 # adding -s (silent) flag, to have a silent install.
1630 # only updater will be verbose
1631 #
1632 # Revision 1.85  2004/06/17 15:19:44  tipaul
1633 # missing Marc_Search index on marc_word
1634 #
1635 # Revision 1.84  2004/06/17 08:25:21  tipaul
1636 # DB modifs : merging tag & subfield in marc_word table
1637 #
1638 # Revision 1.83  2004/06/10 08:32:02  tipaul
1639 # MARC authority management (continued)
1640 #
1641 # Revision 1.82  2004/06/03 12:46:58  tipaul
1642 # * frameworks and itemtypes are independant
1643 #
1644 # 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.
1645 #
1646 # Revision 1.81  2004/05/28 09:56:21  tipaul
1647 # bugfix
1648 #
1649 # Revision 1.80  2004/05/28 08:32:00  tipaul
1650 # adding :
1651 # * MARC authority file
1652 # * seealso & hidden in MARC biblio structure.
1653 #
1654 # Revision 1.79  2004/05/18 09:50:07  tipaul
1655 # *** empty log message ***
1656 #
1657 # Revision 1.78  2004/05/10 09:29:33  tipaul
1658 # css is now the default theme for OPAC.
1659 # It will be the theme used for improvements and new things in OPAC.
1660 #
1661 # Revision 1.77  2004/05/06 14:56:51  tipaul
1662 # adding table issuingrules (previously called categoryitem
1663 #
1664 # Revision 1.76  2004/05/03 09:32:25  tipaul
1665 # adding printcirculationsplit parameter (already existed, but was not in systempref by defaul)
1666 #
1667 # Revision 1.75  2004/04/14 19:49:00  tipaul
1668 # seealso field set to 255 chars
1669 #
1670 # Revision 1.74  2004/03/11 16:10:16  tipaul
1671 # *** empty log message ***
1672 #
1673 # Revision 1.73  2004/03/06 20:26:13  tipaul
1674 # adding seealso feature in MARC searches
1675 #