removing some useless tables from updatedatabase
[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 strict;
16
17 # CPAN modules
18 use DBI;
19 use Getopt::Long;
20 # Koha modules
21 use C4::Context;
22
23 use MARC::Record;
24 use MARC::File::XML ( BinaryEncoding => 'utf8' );
25  
26 # FIXME - The user might be installing a new database, so can't rely
27 # on /etc/koha.conf anyway.
28
29 my $debug = 0;
30
31 my (
32     $sth, $sti,
33     $query,
34     %existingtables,    # tables already in database
35     %types,
36     $table,
37     $column,
38     $type, $null, $key, $default, $extra,
39     $prefitem,          # preference item in systempreferences table
40 );
41
42 my $silent;
43 GetOptions(
44     's' =>\$silent
45     );
46 my $dbh = C4::Context->dbh;
47 print "connected to your DB. Checking & modifying it\n" unless $silent;
48 $|=1; # flushes output
49
50 #-------------------
51 # Defines
52
53 # Tables to add if they don't exist
54 my %requiretables = (
55     action_logs     => "(
56                     `timestamp` TIMESTAMP NOT NULL ,
57                     `user` INT( 11 ) NOT NULL ,
58                     `module` TEXT default '',
59                     `action` TEXT default '' ,
60                     `object` INT(11) NULL ,
61                     `info` TEXT default '' ,
62                     PRIMARY KEY ( `timestamp` , `user` )
63                 )",
64     letter        => "(
65                     module varchar(20) NOT NULL default '',
66                     code varchar(20) NOT NULL default '',
67                     name varchar(100) NOT NULL default '',
68                     title varchar(200) NOT NULL default '',
69                     content text,
70                     PRIMARY KEY  (module,code)
71                 )",
72     alert        =>"(
73                     alertid int(11) NOT NULL auto_increment,
74                     borrowernumber int(11) NOT NULL default '0',
75                     type varchar(10) NOT NULL default '',
76                     externalid varchar(20) NOT NULL default '',
77                     PRIMARY KEY  (alertid),
78                     KEY borrowernumber (borrowernumber),
79                     KEY type (type,externalid)
80                 )",
81     opac_news => "(
82                 `idnew` int(10) unsigned NOT NULL auto_increment,
83                 `title` varchar(250) NOT NULL default '',
84                 `new` text NOT NULL,
85                 `lang` varchar(4) NOT NULL default '',
86                 `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
87                 PRIMARY KEY  (`idnew`)
88                 )",
89     repeatable_holidays => "(
90                 `id` int(11) NOT NULL auto_increment,
91                 `branchcode` varchar(4) NOT NULL default '',
92                 `weekday` smallint(6) default NULL,
93                 `day` smallint(6) default NULL,
94                 `month` smallint(6) default NULL,
95                 `title` varchar(50) NOT NULL default '',
96                 `description` text NOT NULL,
97                 PRIMARY KEY  (`id`)
98                 )",
99     special_holidays => "(
100                 `id` int(11) NOT NULL auto_increment,
101                 `branchcode` varchar(4) NOT NULL default '',
102                 `day` smallint(6) NOT NULL default '0',
103                 `month` smallint(6) NOT NULL default '0',
104                 `year` smallint(6) NOT NULL default '0',
105                 `isexception` smallint(1) NOT NULL default '1',
106                 `title` varchar(50) NOT NULL default '',
107                 `description` text NOT NULL,
108                 PRIMARY KEY  (`id`)
109                 )",
110     overduerules    =>"(`branchcode` varchar(255) NOT NULL default '',
111                     `categorycode` char(2) NOT NULL default '',
112                     `delay1` int(4) default '0',
113                     `letter1` varchar(20) default NULL,
114                     `debarred1` char(1) default '0',
115                     `delay2` int(4) default '0',
116                     `debarred2` char(1) default '0',
117                     `letter2` varchar(20) default NULL,
118                     `delay3` int(4) default '0',
119                     `letter3` varchar(20) default NULL,
120                     `debarred3` int(1) default '0',
121                     PRIMARY KEY  (`branchcode`,`categorycode`)
122                     )",
123     cities            => "(`cityid` int auto_increment,
124                         `city_name` char(100) NOT NULL,
125                         `city_zipcode` char(20),
126                         PRIMARY KEY (`cityid`)
127                     )",
128     roadtype            => "(`roadtypeid` int auto_increment,
129                         `road_type` char(100) NOT NULL,
130                         PRIMARY KEY (`roadtypeid`)
131                     )",
132
133     labels                     => "(
134                 labelid int(11) NOT NULL auto_increment,
135                                itemnumber varchar(100) NOT NULL default '',
136                                timestamp timestamp(14) NOT NULL,
137                                PRIMARY KEY  (labelid)
138                                )",
139
140     labels_conf                => "(
141                 id int(4) NOT NULL auto_increment,
142                                barcodetype char(100) default '',
143                                title tinyint(1) default '0',
144                                isbn tinyint(1) default '0',
145                                itemtype tinyint(1) default '0',
146                                barcode tinyint(1) default '0',
147                                dewey tinyint(1) default '0',
148                                class tinyint(1) default '0',
149                                author tinyint(1) default '0',
150                                papertype char(100) default '',
151                                startrow int(2) default NULL,
152                                PRIMARY KEY  (id)
153                                )",
154        reviews                  => "(
155                             reviewid integer NOT NULL auto_increment,
156                             borrowernumber integer,
157                             biblionumber integer,
158                             review text,
159                             approved tinyint,
160                             datereviewed datetime,
161                             PRIMARY KEY (reviewid)
162                             )",
163     subscriptionroutinglist=>"(
164                              routingid integer NOT NULL auto_increment,
165                              borrowernumber integer,
166                              ranking integer,
167                              subscriptionid integer,
168                             PRIMARY KEY (routingid)
169                              )",
170
171     notifys    => "(
172               notify_id int(11) NOT NULL default '0',
173                 `borrowernumber` int(11) NOT NULL default '0',
174               `itemnumber` int(11) NOT NULL default '0',
175               `notify_date` date NOT NULL default '0000-00-00',
176                       `notify_send_date` date default NULL,
177                       `notify_level` int(1) NOT NULL default '0',
178                       `method` varchar(20) NOT NULL default ''
179               )",
180
181    charges    => "(
182               `charge_id` varchar(5) NOT NULL default '',
183                 `description` text NOT NULL,
184                 `amount` decimal(28,6) NOT NULL default '0.000000',
185                           `min` int(4) NOT NULL default '0',
186                 `max` int(4) NOT NULL default '0',
187                           `level` int(1) NOT NULL default '0',
188                           PRIMARY KEY  (`charge_id`)
189               )",
190     tags => "(
191         `entry` varchar(255) NOT NULL default '',
192         `weight` bigint(20) NOT NULL default '0',
193          PRIMARY KEY  (`entry`)
194     )
195     ",
196    zebraqueue    => "(
197                 `id` int NOT NULL auto_increment,
198                 `biblio_auth_number` int NOT NULL,
199                 `operation` char(20) NOT NULL,
200                 `server` char(20) NOT NULL ,
201                 PRIMARY KEY  (`id`)
202               ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci AUTO_INCREMENT=1",
203
204 );
205
206 my %requirefields = (
207     subscription => { 'letter' => 'char(20) NULL', 'distributedto' => 'text NULL', 'firstacquidate'=>'date NOT NULL','irregularity'=>'TEXT NULL default \'\'','numberpattern'=>'TINYINT(3) NULL default 0', 'callnumber'=>'text NULL', 'hemisphere' =>'TINYINT(3) NULL default 0', 'issuesatonce'=>'TINYINT(3) NOT NULL default 1',  'branchcode' =>'varchar(12) NOT NULL default \'\'', 'manualhistory'=>'TINYINT(1) NOT NULL default 0','internalnotes'=>'LONGTEXT NULL default \'\''},
208     itemtypes => { 'imageurl' => 'char(200) NULL'},
209     aqbookfund => { 'branchcode' => 'varchar(4) NULL'},
210     aqbudget => { 'branchcode' => 'varchar(4) NULL'},
211     auth_header => { 'marc' => 'BLOB NOT NULL', 'linkid' => 'BIGINT(20) NULL'},
212     auth_subfield_structure =>{ 'hidden' => 'TINYINT(3) NOT NULL default 0', 'kohafield' => 'VARCHAR(45) NOT NULL', 'linkid' =>  'TINYINT(1) NOT NULL default 0', 'isurl' => 'TINYINT(1)', 'frameworkcode'=>'VARCHAR(8) NOT  NULL'},
213     marc_breeding => { 'isbn' => 'varchar(13) NOT NULL'},
214     serial =>{ 'publisheddate' => 'date', 'claimdate' => 'date', 'itemnumber'=>'text NULL','routingnotes'=>'text NULL',},
215     statistics => { 'associatedborrower' => 'integer'},
216     z3950servers =>{  "name" =>"text",  "description" => "text NOT NULL",
217                     "position" =>"enum('primary','secondary','') NOT NULL default 'primary'",  "icon" =>"text",
218                     "type" =>"enum('zed','opensearch') NOT NULL default 'zed'",
219                     },
220     issues =>{ 'issuedate'=>"date NOT NULL default '0000-00-00'", },
221
222 #    tablename        => { 'field' => 'fieldtype' },
223 );
224
225 # Enter here the table to delete.
226 my @TableToDelete = qw(
227     additionalauthors
228     bibliosubject
229     bibliosubtitle
230     bibliothesaurus
231 );
232
233 my %uselessfields = (
234 # tablename => "field1,field2",
235     borrowers => "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
236     deletedborrowers=> "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
237     );
238 # the other hash contains other actions that can't be done elsewhere. they are done
239 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
240
241 # The tabledata hash contains data that should be in the tables.
242 # The uniquefieldrequired hash entry is used to determine which (if any) fields
243 # must not exist in the table for this row to be inserted.  If the
244 # uniquefieldrequired entry is already in the table, the existing data is not
245 # modified, unless the forceupdate hash entry is also set.  Fields in the
246 # anonymous "forceupdate" hash will be forced to be updated to the default
247 # values given in the %tabledata hash.
248
249 my %tabledata = (
250 # tablename => [
251 #    {    uniquefielrequired => 'fieldname', # the primary key in the table
252 #        fieldname => fieldvalue,
253 #        fieldname2 => fieldvalue2,
254 #    },
255 # ],
256     systempreferences => [
257         {
258             uniquefieldrequired => 'variable',
259             variable            => 'useDaysMode',
260             value               => 'Calendar',
261             forceupdate         => { 'explanation' => 1,
262                                      'type' => 1},
263             explanation            => 'How to calculate return dates : Calendar means holidays will be controled, Days means the return date don\'t depend on holidays',
264             type        => 'Choice',
265             options        => 'Calendar|Days'
266         },
267         {
268             uniquefieldrequired => 'variable',
269             variable            => 'BorrowersTitles',
270             value               => 'Mr|Mrs|Miss|Ms',
271             forceupdate         => { 'explanation' => 1,
272                                      'type' => 1},
273             explanation         => 'List all Titles for borrowers',
274             type                => 'free',
275         },
276         {
277             uniquefieldrequired => 'variable',
278             variable            => 'BorrowerMandatoryField',
279             value               => 'cardnumber|surname|address',
280             forceupdate         => { 'explanation' => 1,
281                                      'type' => 1},
282             explanation         => 'List all mandatory fields for borrowers',
283             type                => 'free',
284         },
285         {
286             uniquefieldrequired => 'variable',
287             variable            => 'borrowerRelationship',
288             value               => 'father|mother,grand-mother',
289             forceupdate         => { 'explanation' => 1,
290                                      'type' => 1},
291             explanation         => 'The relationships between a guarantor & a guarantee (separated by | or ,)',
292             type                => 'free',
293         },
294         {
295             uniquefieldrequired => 'variable',
296             variable            => 'ReservesMaxPickUpDelay',
297             value               => '10',
298             forceupdate         => { 'explanation' => 1,
299                                      'type' => 1},
300             explanation         => 'Maximum delay to pick up a reserved document',
301             type                => 'free',
302         },
303         {
304             uniquefieldrequired => 'variable',
305             variable            => 'TransfersMaxDaysWarning',
306             value               => '3',
307             forceupdate         => { 'explanation' => 1,
308                                      'type' => 1},
309             explanation         => 'Max delay before considering the transfer has potentialy a problem',
310             type                => 'free',
311         },
312         {
313             uniquefieldrequired => 'variable',
314             variable            => 'memberofinstitution',
315             value               => '0',
316             forceupdate         => { 'explanation' => 1,
317                                      'type' => 1},
318             explanation         => 'Are your patrons members of institutions',
319             type                => 'YesNo',
320         },
321     {
322             uniquefieldrequired => 'variable',
323             variable            => 'ReadingHistory',
324             value               => '0',
325             forceupdate         => { 'explanation' => 1,
326                                      'type' => 1},
327             explanation         => 'Allow reading record info retrievable from issues and oldissues tables',
328             type                => 'YesNo',
329         },
330     {
331             uniquefieldrequired => 'variable',
332             variable            => 'IssuingInProcess',
333             value               => '0',
334             forceupdate         => { 'explanation' => 1,
335                                      'type' => 1},
336             explanation         => 'Allow no debt alert if the patron is issuing item that accumulate debt',
337             type                => 'YesNo',
338         },
339     {
340             uniquefieldrequired => 'variable',
341             variable            => 'AutomaticItemReturn',
342             value               => '1',
343             forceupdate         => { 'explanation' => 1,
344                                      'type' => 1},
345             explanation         => 'This Variable allow or not to return automaticly to his homebranch',
346             type                => 'YesNo',
347         },
348     {
349             uniquefieldrequired => 'variable',
350             variable            => 'reviewson',
351             value               => '0',
352             forceupdate         => { 'explanation' => 1,
353                                      'type' => 1},
354             explanation         => 'Allows patrons to submit reviews from the opac',
355             type                => 'YesNo',
356         },
357     {
358             uniquefieldrequired => 'variable',
359             variable            => 'intranet_includes',
360             value               => 'includes',
361             forceupdate         => { 'explanation' => 1,
362                                      'type' => 1},
363             explanation         => 'The includes directory you want for specific look of Koha (includes or includes_npl for example)',
364             type                => 'Free',
365         },
366         {
367             uniquefieldrequired => 'variable',
368             variable            => 'AutoLocation',
369             value               => '0',
370             forceupdate         => { 'explanation' => 1,
371                                      'type' => 1},
372             explanation         => 'switch to activate or not Autolocation, if Yes, the Librarian can\'t change his location, it\'s defined by branchip',
373             type                => 'YesNo',
374         },
375         {
376             uniquefieldrequired => 'variable',
377             variable            => 'serialsadditems',
378             value               => '0',
379             forceupdate         => {
380                 'explanation' => 1,
381                 'type' => 1
382             },
383             explanation => 'If set, a new item will be automatically added when receiving an issue',
384             type => 'YesNo',
385         },
386         {
387             uniquefieldrequired => 'variable',
388             variable            => 'expandedSearchOption',
389             value               => '0',
390             forceupdate         => {
391                 'explanation' => 1,
392                 'type' => 1
393             },
394             explanation => 'search among marc field',
395             type => 'YesNo',
396         },
397        {
398             uniquefieldrequired => 'variable',
399             variable            => 'RequestOnOpac',
400             value               => '1',
401             forceupdate         => { 'explanation' => 1,
402                                      'type' => 1},
403             explanation         => 'option to allow reserves on opac',
404             type                => 'YesNo',
405         },
406        {
407             uniquefieldrequired => 'variable',
408             variable            => 'OpacCloud',
409             value               => '1',
410             forceupdate         => { 'explanation' => 1,
411                                      'type' => 1},
412             explanation         => 'Enable / Disable cloud link on OPAC (Require to run misc/cronjobs/build_browser_and_cloud.pl on the server)',
413             type                => 'YesNo',
414         },
415        {
416             uniquefieldrequired => 'variable',
417             variable            => 'OpacBrowser',
418             value               => '1',
419             forceupdate         => { 'explanation' => 1,
420                                      'type' => 1},
421             explanation         => 'Enable/Disable browser link on OPAC (Require to run misc/cronjobs/build_browser_and_cloud.pl on the server)',
422             type                => 'YesNo',
423         },
424        {
425             uniquefieldrequired => 'variable',
426             variable            => 'OpacTopissue',
427             value               => '1',
428             forceupdate         => { 'explanation' => 1,
429                                      'type' => 1},
430             explanation         => 'Enable / Disable the top issue link on OPAC',
431             type                => 'YesNo',
432         },
433        {
434             uniquefieldrequired => 'variable',
435             variable            => 'OpacAuthorities',
436             value               => '1',
437             forceupdate         => { 'explanation' => 1,
438                                      'type' => 1},
439             explanation         => 'Enable / Disable the search authority link on OPAC',
440             type                => 'YesNo',
441         },
442         {
443             uniquefieldrequired => 'variable',
444             variable            => 'CataloguingLog',
445             value               => '0',
446             forceupdate         => {'explanation' => 1, 'type' => 1},
447             explanation         => 'Active this if you want to log cataloguing action.',
448             type                => 'YesNo',
449         },
450         {
451             uniquefieldrequired => 'variable',
452             variable            => 'BorrowersLog',
453             value               => '0',
454             forceupdate         => {'explanation' => 1, 'type' => 1},
455             explanation         => 'Active this if you want to log borrowers edition/creation/deletion...',
456             type                => 'YesNo',
457         },
458         {
459             uniquefieldrequired => 'variable',
460             variable            => 'SubscriptionLog',
461             value               => '0',
462             forceupdate         => {'explanation' => 1, 'type' => 1},
463             explanation         => 'Active this if you want to log Subscription action',
464             type                => 'YesNo',
465         },
466         {
467             uniquefieldrequired => 'variable',
468             variable            => 'IssueLog',
469             value               => '0',
470             forceupdate         => {'explanation' => 1, 'type' => 1},
471             explanation         => 'Active this if you want to log issue.',
472             type                => 'YesNo',
473         },
474         {
475             uniquefieldrequired => 'variable',
476             variable            => 'ReturnLog',
477             value               => '0',
478             forceupdate         => {'explanation' => 1, 'type' => 1},
479             explanation         => 'Active this if you want to log the circulation return',
480             type                => 'YesNo',
481         },
482         {
483             uniquefieldrequired => 'variable',
484             variable            => 'Version',
485             value               => '3.0',
486             forceupdate         => {'explanation' => 1, 'type' => 1},
487             explanation         => 'Koha Version',
488             type                => 'Free',
489         },
490         {   
491             uniquefieldrequired => 'variable',
492             variable            => 'LetterLog',
493             value               => '0',
494             forceupdate         => {'explanation' => 1, 'type' => 1},
495             explanation         => 'Active this if you want to log all the letter sent',
496             type                => 'YesNo',
497         },
498         {
499             uniquefieldrequired => 'variable',
500             variable            => 'FinesLog',
501             value               => '0',
502             forceupdate         => {'explanation' => 1, 'type' => 1},
503             explanation         => 'Active this if you want to log fines',
504             type                => 'YesNo',
505         },
506         {
507             uniquefieldrequired => 'variable',
508             variable            => 'NoZebra',
509             value               => '0',
510             forceupdate         => {'explanation' => 1, 'type' => 1},
511             explanation         => 'Active this if you want NOT to use zebra (large libraries should avoid this parameters)',
512             type                => 'YesNo',
513         },
514         {
515             uniquefieldrequired => 'variable',
516             variable            => 'NoZebraIndexes',
517             value               => '0',
518             forceupdate         => {'explanation' => 1, 'type' => 1},
519             explanation         => "Enter a specific hash for NoZebra indexes. Enter : 'indexname' => '100a,245a,500*','index2' => '...'",
520             type                => 'Free',
521         },
522     ],
523     userflags => [
524         {
525             uniquefieldrequired => 'bit',
526             bit                 => '14',
527             flag                => 'editauthorities',
528             flagdesc            => 'allow to edit authorities',
529             defaulton           => '0',
530         },
531         {
532             uniquefieldrequired => 'bit',
533             bit                 => '15',
534             flag                 => 'serials',
535             flagdesc            => 'allow to manage serials subscriptions',
536             defaulton           => '0',
537         },
538         {
539             uniquefieldrequired => 'bit',
540             bit                 => '16',
541             flag                 => 'reports',
542             flagdesc            => 'allow to access to the reports module',
543             defaulton           => '0',
544         },
545     ],
546     authorised_values => [
547         {
548             uniquefieldrequired => 'id',
549             category            => 'SUGGEST',
550             authorised_value    => 'Not enough budget',
551             lib                 => 'This book it too much expensive',
552         }
553     ],
554 );
555
556 my %fielddefinitions = (
557 # fieldname => [
558 #    {          field => 'fieldname',
559 #             type    => 'fieldtype',
560 #             null    => '',
561 #             key     => '',
562 #             default => ''
563 #         },
564 #     ],
565     aqbasket =>  [
566         {
567             field    => 'booksellerid',
568             type    => 'int(11)',
569             null    => 'NOT NULL',
570             key        => '',
571             default    => '1',
572             extra    => '',
573         },
574     ],
575     aqbooksellers =>  [
576         {
577             field    => 'id',
578             type    => 'int(11)',
579             null    => 'NOT NULL',
580             key        => 'PRI',
581             default    => '',
582             extra    => 'auto_increment',
583         },
584         {
585             field    => 'listprice',
586             type    => 'varchar(10)',
587             null    => 'NULL',
588             key        => '',
589             default    => '',
590             extra    => '',
591         },
592         {
593             field    => 'invoiceprice',
594             type    => 'varchar(10)',
595             null    => 'NULL',
596             key        => '',
597             default    => '',
598             extra    => '',
599         },
600     ],
601     
602     accountlines =>  [
603         {
604             field    => 'notify_id',
605             type    => 'int(11)',
606             null    => 'NOT NULL',
607             key        => '',
608             default    => '0',
609             extra    => '',
610         },
611         {
612             field    => 'notify_level',
613             type    => 'int(2)',
614             null    => 'NOT NULL',
615             key        => '',
616             default    => '0',
617             extra    => '',
618         },
619     
620     ],
621     
622     borrowers => [
623         {    field => 'firstname',
624              type => 'text',
625              null => 'NULL',
626          },
627         {    field => 'initials',
628              type => 'text',
629              null => 'NULL',
630          },
631         {    field => 'B_email',
632              type => 'text',
633              null => 'NULL',
634              after => 'B_zipcode',
635          },
636          {
637             field => 'streetnumber', # street number (hidden if streettable table is empty)
638             type => 'char(10)',
639             null => 'NULL',
640             after => 'initials',
641         },
642         {
643             field => 'streettype', # street table, list builded from a system table
644             type => 'char(50)',
645             null => 'NULL',
646             after => 'streetnumber',
647         },
648         {    field => 'phone',
649              type => 'text',
650              null => 'NULL',
651          },
652         {
653             field => 'B_streetnumber', # street number (hidden if streettable table is empty)
654             type => 'char(10)',
655             null => 'NULL',
656             after => 'fax',
657         },
658         {
659             field => 'B_streettype', # street table, list builded from a system table
660             type => 'char(50)',
661             null => 'NULL',
662             after => 'B_streetnumber',
663         },
664         {
665             field => 'phonepro',
666             type => 'text',
667             null => 'NULL',
668             after => 'fax',
669         },
670         {
671             field => 'address2', # complement address
672             type => 'text',
673             null => 'NULL',
674             after => 'address',
675         },
676         {
677             field => 'emailpro',
678             type => 'text',
679             null => 'NULL',
680             after => 'fax',
681         },
682         {
683             field => 'contactfirstname', # contact's firstname
684             type => 'text',
685             null => 'NULL',
686             after => 'contactname',
687         },
688         {
689             field => 'contacttitle', # contact's title
690             type => 'text',
691             null => 'NULL',
692             after => 'contactfirstname',
693         },
694         {
695             field => 'branchcode',
696             type  => 'varchar(10)',
697             null  => 'NOT NULL',
698             default    => '',
699             extra => '',
700         },
701         {
702             field => 'categorycode',
703             type  => 'varchar(10)',
704             null  => 'NOT NULL',
705             default    => '',
706             extra => '',
707         }
708     ],
709     
710     biblioitems =>  [
711         {
712             field    => 'lcsort',
713             type    => 'varchar(25)',
714             null    => 'NULL',
715             key        => '',
716             default    => '',
717             extra    => '',
718         },
719         {
720             field    => 'ccode',
721             type    => 'varchar(4)',
722             null    => 'NULL',
723             key        => '',
724             default    => '',
725             extra    => '',
726         },
727         {
728             field   => 'dewey',
729             type    => 'varchar(30)',
730             null    => 'null',
731             default => '',
732             extra   => '',
733         },
734     ],
735     deletedbiblioitems => [
736         {
737             field   => 'dewey',
738             type    => 'varchar(30)',
739             null    => 'null',
740             default => '',
741             extra   => '',
742         },
743     ],
744     branches =>  [
745         {
746             field    => 'branchip',
747             type    => 'varchar(15)',
748             null    => 'NULL',
749             key        => '',
750             default    => '',
751             extra    => '',
752         },
753         {
754             field    => 'branchprinter',
755             type    => 'varchar(100)',
756             null    => 'NULL',
757             key        => '',
758             default    => '',
759             extra    => '',
760         },
761         {
762             field   => 'branchcode',
763             type    => 'varchar(10)',
764             null    => 'NOT NULL',
765             default => '',
766             extra   => '',
767         }
768     ],
769     branchtransfers =>[
770         {
771             field   => 'frombranch',
772             type    => 'VARCHAR(10)',
773             null    => 'NOT NULL',
774             key     => '',
775             default => '',
776             extra   => '',
777         },
778         {
779             field   => 'tobranch',
780             type    => 'VARCHAR(10)',
781             null    => 'NOT NULL',
782             key     => '',
783             default => '',
784         }
785     ],
786     
787     categories =>  [
788         {
789             field    => 'category_type',
790             type    => 'char(1)',
791             null    => 'NOT NULL',
792             key        => '',
793             default    => 'A',
794             extra    => '',
795         },
796         {
797             field   => 'categorycode',
798             type    => 'varchar(10)',
799             null    => 'NOT NULL',
800             key     => 'PRI',
801             default => '',
802             extra   => '',
803         },
804     ],
805     
806     deletedborrowers => [
807         {    field => 'firstname',
808              type => 'text',
809              null => 'NULL',
810          },
811         {    field => 'initials',
812              type => 'text',
813              null => 'NULL',
814          },
815         {    field => 'B_email',
816              type => 'text',
817              null => 'NULL',
818              after => 'B_zipcode',
819          },
820          {
821             field => 'streetnumber', # street number (hidden if streettable table is empty)
822             type => 'char(10)',
823             null => 'NULL',
824             after => 'initials',
825         },
826         {
827             field => 'streettype', # street table, list builded from a system table
828             type => 'char(50)',
829             null => 'NULL',
830             after => 'streetnumber',
831         },
832         {    field => 'phone',
833              type => 'text',
834              null => 'NULL',
835          },
836          {
837             field => 'B_streetnumber', # street number (hidden if streettable table is empty)
838             type => 'char(10)',
839             null => 'NULL',
840             after => 'fax',
841         },
842         {
843             field => 'B_streettype', # street table, list builded from a system table
844             type => 'char(50)',
845             null => 'NULL',
846             after => 'B_streetnumber',
847         },
848         {
849             field => 'phonepro',
850             type => 'text',
851             null => 'NULL',
852             after => 'fax',
853         },
854         {
855             field => 'address2', # complement address
856             type => 'text',
857             null => 'NULL',
858             after => 'address',
859         },
860         {
861             field => 'emailpro',
862             type => 'text',
863             null => 'NULL',
864             after => 'fax',
865         },
866         {
867             field => 'contactfirstname', # contact's firstname
868             type => 'text',
869             null => 'NULL',
870             after => 'contactname',
871         },
872         {
873             field => 'contacttitle', # contact's title
874             type => 'text',
875             null => 'NULL',
876             after => 'contactfirstname',
877         },
878     ],
879     
880     issues =>  [
881         {
882             field    => 'borrowernumber',
883             type    => 'int(11)',
884             null    => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
885             key        => '',
886             default    => '',
887             extra    => '',
888         },
889         {
890             field    => 'itemnumber',
891             type    => 'int(11)',
892             null    => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
893             key        => '',
894             default    => '',
895             extra    => '',
896         },
897         {
898             field   => 'branchcode',
899             type    => 'varchar(10)',
900             null    => 'NULL',
901             key     => '',
902             default => '',
903             extra   => '',
904         },
905         {
906             field   => 'issuedate',
907             type    => 'date',
908             null    => '',
909             key     => '',
910             default => '0000-00-00',
911             extra   => '',
912         },
913     ],
914     
915     items => [
916         {
917             field    => 'onloan',
918             type    => 'date',
919             null    => 'NULL',
920             key        => '',
921             default    => '0000-00-00',
922             extra    => '',
923         },
924         {
925             field    => 'cutterextra',
926             type    => 'varchar(45)',
927             null    => 'NULL',
928             key        => '',
929             default    => '',
930             extra    => '',
931         },
932         {
933             field    => 'issue_date',
934             type    => 'date',
935             null    => 'NULL',
936             key        => '',
937             default    => '',
938             extra    => '',
939         },
940         {
941             field    => 'homebranch',
942             type    => 'varchar(10)',
943             null    => 'NULL',
944             key        => '',
945             default    => '',
946             extra    => '',
947         },
948         {
949             field    => 'holdingbranch',
950             type    => 'varchar(10)',
951             null    => 'NULL',
952             key        => '',
953             default    => '',
954             extra    => '',
955         },
956         {
957             field    => 'itype',
958             type    => 'varchar(10)',
959             null    => 'NULL',
960             key        => '',
961             default    => '',
962             extra    => '',
963         },
964     ],
965     itemtypes => [
966         {
967             field  => 'itemtype',
968             type   => 'varchar(10)',
969             default    => '',
970             null   => 'NOT NULL',
971             key    => 'PRI',
972             extra  => 'UNIQUE',
973         },
974         {
975             field  => 'summary',
976             type   => 'TEXT',
977             null   => 'NULL',
978             key    => '',
979             extra  => '',
980         },
981     ],
982     marc_breeding => [
983         {
984             field => 'marc',
985             type  => 'LONGBLOB',
986             null  => 'NULL',
987             key    => '',
988             extra  => '',
989         }
990     ],
991     marc_subfield_structure => [
992         {
993             field => 'defaultvalue',
994             type  => 'TEXT',
995             null  => 'NULL',
996             key    => '',
997             extra  => '',
998         }
999     ],
1000     opac_news => [
1001         {
1002             field  => 'expirationdate',
1003             type   => 'date',
1004             null   => 'null',
1005             key    => '',
1006             extra  => '',
1007         },
1008         {
1009             field   => 'number',
1010             type    => 'int(11)',
1011             null    => 'NULL',
1012             key     => '',
1013             default => '0',
1014             extra   => '',
1015         },
1016     ],
1017     reserves =>  [
1018         {
1019             field    => 'waitingdate',
1020             type    => 'date',
1021             null    => 'NULL',
1022             key        => '',
1023             default    => '',
1024             extra    => '',
1025         },
1026     ],
1027     serial => [
1028         {
1029             field   => 'notes',
1030             type    => 'TEXT',
1031             null    => 'NULL',
1032             key     => '',
1033             default => '',
1034             extra   => ''
1035         },
1036     ],
1037     shelfcontents => [
1038         {
1039             field => 'dateadded',
1040             type => 'timestamp',
1041             null    => 'NULL',
1042         },
1043     ],
1044     systempreferences =>  [
1045         {
1046             field    => 'value',
1047             type    => 'text',
1048             null    => 'NULL',
1049             key        => '',
1050             default    => '',
1051             extra    => '',
1052         },
1053         {
1054             field    => 'explanation',
1055             type    => 'text',
1056             null    => 'NULL',
1057             key        => '',
1058             default    => '',
1059             extra    => '',
1060         },
1061     ],
1062     suggestions => [
1063         {
1064             field   => 'reason',
1065             type    => 'text',
1066             null    => 'NULL',
1067             key     => ''  ,
1068             default => '',
1069             extra   =>    '',
1070         }
1071     ],
1072 );
1073
1074 my %indexes = (
1075 #    table => [
1076 #         {    indexname => 'index detail'
1077 #         }
1078 #    ],
1079     aqbooksellers => [
1080         {    indexname => 'PRIMARY',
1081             content => 'id',
1082             type => 'PRI',
1083         }
1084     ],
1085     aqbasket => [
1086         {    indexname => 'booksellerid',
1087             content => 'booksellerid',
1088         },
1089     ],
1090     aqorders => [
1091         {    indexname => 'basketno',
1092             content => 'basketno',
1093         },
1094     ],
1095     aqorderbreakdown => [
1096         {    indexname => 'ordernumber',
1097             content => 'ordernumber',
1098         },
1099         {    indexname => 'bookfundid',
1100             content => 'bookfundid',
1101         },
1102     ],
1103     biblioitems => [
1104         {    indexname => 'isbn',
1105             content => 'isbn',
1106         },
1107         {    indexname => 'publishercode',
1108             content => 'publishercode',
1109         },
1110     ],
1111     branches => [
1112         {
1113             indexname => 'branchcode',
1114             content   => 'branchcode',
1115             type => 'PRI',
1116         }
1117     ],
1118     branchrelations => [
1119         {
1120             indexname => 'PRIMARY',
1121             content => 'categorycode',
1122             type => 'PRI',
1123         }
1124     ],
1125     branchrelations => [
1126         {    indexname => 'PRIMARY',
1127             content => 'branchcode,categorycode',
1128             type => 'PRI',
1129         },
1130         {    indexname => 'branchcode',
1131             content => 'branchcode',
1132         },
1133         {    indexname => 'categorycode',
1134             content => 'categorycode',
1135         }
1136     ],
1137     currency => [
1138         {    indexname => 'PRIMARY',
1139             content => 'currency',
1140             type => 'PRI',
1141         }
1142     ],
1143     categories => [
1144         {
1145             indexname => 'categorycode',
1146             content   => 'categorycode',
1147         }
1148     ],
1149     items => [
1150         {    indexname => 'homebranch',
1151             content => 'homebranch',
1152         },
1153         {    indexname => 'holdingbranch',
1154             content => 'holdingbranch',
1155         }
1156     ],
1157     itemtypes => [
1158         {
1159             indexname => 'itemtype',
1160             content   => 'itemtype',
1161         }
1162     ],
1163     shelfcontents => [
1164         {    indexname => 'shelfnumber',
1165             content => 'shelfnumber',
1166         },
1167         {    indexname => 'itemnumber',
1168             content => 'itemnumber',
1169         }
1170     ],
1171         userflags => [
1172                 {       indexname => 'PRIMARY',
1173                         content => 'bit',
1174                         type => 'PRI',
1175                 }
1176         ]
1177 );
1178
1179 my %foreign_keys = (
1180 #    table => [
1181 #         {    key => 'the key in table' (must be indexed)
1182 #            foreigntable => 'the foreigntable name', # (the parent)
1183 #            foreignkey => 'the foreign key column(s)' # (in the parent)
1184 #            onUpdate => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1185 #            onDelete => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1186 #         }
1187 #    ],
1188     branchrelations => [
1189         {    key => 'branchcode',
1190             foreigntable => 'branches',
1191             foreignkey => 'branchcode',
1192             onUpdate => 'CASCADE',
1193             onDelete => 'CASCADE',
1194         },
1195         {    key => 'categorycode',
1196             foreigntable => 'branchcategories',
1197             foreignkey => 'categorycode',
1198             onUpdate => 'CASCADE',
1199             onDelete => 'CASCADE',
1200         },
1201     ],
1202     shelfcontents => [
1203         {    key => 'shelfnumber',
1204             foreigntable => 'bookshelf',
1205             foreignkey => 'shelfnumber',
1206             onUpdate => 'CASCADE',
1207             onDelete => 'CASCADE',
1208         },
1209         {    key => 'itemnumber',
1210             foreigntable => 'items',
1211             foreignkey => 'itemnumber',
1212             onUpdate => 'CASCADE',
1213             onDelete => 'CASCADE',
1214         },
1215     ],
1216     # onDelete is RESTRICT on reference tables (branches, itemtype) as we don't want items to be
1217     # easily deleted, but branches/itemtype not too easy to empty...
1218     biblioitems => [
1219         {    key => 'biblionumber',
1220             foreigntable => 'biblio',
1221             foreignkey => 'biblionumber',
1222             onUpdate => 'CASCADE',
1223             onDelete => 'CASCADE',
1224         },
1225         {    key => 'itemtype',
1226             foreigntable => 'itemtypes',
1227             foreignkey => 'itemtype',
1228             onUpdate => 'CASCADE',
1229             onDelete => 'RESTRICT',
1230         },
1231     ],
1232     items => [
1233         {    key => 'biblioitemnumber',
1234             foreigntable => 'biblioitems',
1235             foreignkey => 'biblioitemnumber',
1236             onUpdate => 'CASCADE',
1237             onDelete => 'CASCADE',
1238         },
1239         {    key => 'homebranch',
1240             foreigntable => 'branches',
1241             foreignkey => 'branchcode',
1242             onUpdate => 'CASCADE',
1243             onDelete => 'RESTRICT',
1244         },
1245         {    key => 'holdingbranch',
1246             foreigntable => 'branches',
1247             foreignkey => 'branchcode',
1248             onUpdate => 'CASCADE',
1249             onDelete => 'RESTRICT',
1250         },
1251     ],
1252     aqbasket => [
1253         {    key => 'booksellerid',
1254             foreigntable => 'aqbooksellers',
1255             foreignkey => 'id',
1256             onUpdate => 'CASCADE',
1257             onDelete => 'RESTRICT',
1258         },
1259     ],
1260     aqorders => [
1261         {    key => 'basketno',
1262             foreigntable => 'aqbasket',
1263             foreignkey => 'basketno',
1264             onUpdate => 'CASCADE',
1265             onDelete => 'CASCADE',
1266         },
1267         {    key => 'biblionumber',
1268             foreigntable => 'biblio',
1269             foreignkey => 'biblionumber',
1270             onUpdate => 'SET NULL',
1271             onDelete => 'SET NULL',
1272         },
1273     ],
1274     aqbooksellers => [
1275         {    key => 'listprice',
1276             foreigntable => 'currency',
1277             foreignkey => 'currency',
1278             onUpdate => 'CASCADE',
1279             onDelete => 'CASCADE',
1280         },
1281         {    key => 'invoiceprice',
1282             foreigntable => 'currency',
1283             foreignkey => 'currency',
1284             onUpdate => 'CASCADE',
1285             onDelete => 'CASCADE',
1286         },
1287     ],
1288     aqorderbreakdown => [
1289         {    key => 'ordernumber',
1290             foreigntable => 'aqorders',
1291             foreignkey => 'ordernumber',
1292             onUpdate => 'CASCADE',
1293             onDelete => 'CASCADE',
1294         },
1295         {    key => 'bookfundid',
1296             foreigntable => 'aqbookfund',
1297             foreignkey => 'bookfundid',
1298             onUpdate => 'CASCADE',
1299             onDelete => 'CASCADE',
1300         },
1301     ],
1302     branchtransfers => [
1303         {    key => 'frombranch',
1304             foreigntable => 'branches',
1305             foreignkey => 'branchcode',
1306             onUpdate => 'CASCADE',
1307             onDelete => 'CASCADE',
1308         },
1309         {    key => 'tobranch',
1310             foreigntable => 'branches',
1311             foreignkey => 'branchcode',
1312             onUpdate => 'CASCADE',
1313             onDelete => 'CASCADE',
1314         },
1315         {    key => 'itemnumber',
1316             foreigntable => 'items',
1317             foreignkey => 'itemnumber',
1318             onUpdate => 'CASCADE',
1319             onDelete => 'CASCADE',
1320         },
1321     ],
1322     issuingrules => [
1323         {    key => 'categorycode',
1324             foreigntable => 'categories',
1325             foreignkey => 'categorycode',
1326             onUpdate => 'CASCADE',
1327             onDelete => 'CASCADE',
1328         },
1329         {    key => 'itemtype',
1330             foreigntable => 'itemtypes',
1331             foreignkey => 'itemtype',
1332             onUpdate => 'CASCADE',
1333             onDelete => 'CASCADE',
1334         },
1335     ],
1336     issues => [    # constraint is SET NULL : when a borrower or an item is deleted, we keep the issuing record
1337     # for stat purposes
1338         {    key => 'borrowernumber',
1339             foreigntable => 'borrowers',
1340             foreignkey => 'borrowernumber',
1341             onUpdate => 'SET NULL',
1342             onDelete => 'SET NULL',
1343         },
1344         {    key => 'itemnumber',
1345             foreigntable => 'items',
1346             foreignkey => 'itemnumber',
1347             onUpdate => 'SET NULL',
1348             onDelete => 'SET NULL',
1349         },
1350     ],
1351     reserves => [
1352         {    key => 'borrowernumber',
1353             foreigntable => 'borrowers',
1354             foreignkey => 'borrowernumber',
1355             onUpdate => 'CASCADE',
1356             onDelete => 'CASCADE',
1357         },
1358         {    key => 'biblionumber',
1359             foreigntable => 'biblio',
1360             foreignkey => 'biblionumber',
1361             onUpdate => 'CASCADE',
1362             onDelete => 'CASCADE',
1363         },
1364         {    key => 'itemnumber',
1365             foreigntable => 'items',
1366             foreignkey => 'itemnumber',
1367             onUpdate => 'CASCADE',
1368             onDelete => 'CASCADE',
1369         },
1370         {    key => 'branchcode',
1371             foreigntable => 'branches',
1372             foreignkey => 'branchcode',
1373             onUpdate => 'CASCADE',
1374             onDelete => 'CASCADE',
1375         },
1376     ],
1377     borrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1378     # but prevent deleting a branch as soon as it has 1 borrower !
1379         {    key => 'categorycode',
1380             foreigntable => 'categories',
1381             foreignkey => 'categorycode',
1382             onUpdate => 'RESTRICT',
1383             onDelete => 'RESTRICT',
1384         },
1385         {    key => 'branchcode',
1386             foreigntable => 'branches',
1387             foreignkey => 'branchcode',
1388             onUpdate => 'RESTRICT',
1389             onDelete => 'RESTRICT',
1390         },
1391     ],
1392     deletedborrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1393     # but prevent deleting a branch as soon as it has 1 borrower !
1394         {    key => 'categorycode',
1395             foreigntable => 'categories',
1396             foreignkey => 'categorycode',
1397             onUpdate => 'RESTRICT',
1398             onDelete => 'RESTRICT',
1399         },
1400         {    key => 'branchcode',
1401             foreigntable => 'branches',
1402             foreignkey => 'branchcode',
1403             onUpdate => 'RESTRICT',
1404             onDelete => 'RESTRICT',
1405         },
1406     ],
1407     accountlines => [
1408         {    key => 'borrowernumber',
1409             foreigntable => 'borrowers',
1410             foreignkey => 'borrowernumber',
1411             onUpdate => 'CASCADE',
1412             onDelete => 'CASCADE',
1413         },
1414         {    key => 'itemnumber',
1415             foreigntable => 'items',
1416             foreignkey => 'itemnumber',
1417             onUpdate => 'SET NULL',
1418             onDelete => 'SET NULL',
1419         },
1420     ],
1421     auth_tag_structure => [
1422         {    key => 'authtypecode',
1423             foreigntable => 'auth_types',
1424             foreignkey => 'authtypecode',
1425             onUpdate => 'CASCADE',
1426             onDelete => 'CASCADE',
1427         },
1428     ],
1429     # FIXME : don't constraint auth_*_table and auth_word, as they may be replaced by zebra
1430 );
1431
1432
1433 # column changes
1434 my %column_change = (
1435     # table
1436     borrowers => [
1437                 {
1438                     from => 'emailaddress',
1439                     to => 'email',
1440                     after => 'city',
1441                 },
1442                 {
1443                     from => 'streetaddress',
1444                     to => 'address',
1445                     after => 'initials',
1446                 },
1447                 {
1448                     from => 'faxnumber',
1449                     to => 'fax',
1450                     after => 'phone',
1451                 },
1452                 {
1453                     from => 'textmessaging',
1454                     to => 'opacnote',
1455                     after => 'userid',
1456                 },
1457                 {
1458                     from => 'altnotes',
1459                     to => 'contactnote',
1460                     after => 'opacnote',
1461                 },
1462                 {
1463                     from => 'physstreet',
1464                     to => 'B_address',
1465                     after => 'fax',
1466                 },
1467                 {
1468                     from => 'streetcity',
1469                     to => 'B_city',
1470                     after => 'B_address',
1471                 },
1472                 {
1473                     from => 'phoneday',
1474                     to => 'mobile',
1475                     after => 'phone',
1476                 },
1477                 {
1478                     from => 'zipcode',
1479                     to => 'zipcode',
1480                     after => 'city',
1481                 },
1482                 {
1483                     from => 'homezipcode',
1484                     to => 'B_zipcode',
1485                     after => 'B_city',
1486                 },
1487                 {
1488                     from => 'altphone',
1489                     to => 'B_phone',
1490                     after => 'B_zipcode',
1491                 },
1492                 {
1493                     from => 'expiry',
1494                     to => 'dateexpiry',
1495                     after => 'dateenrolled',
1496                 },
1497                 {
1498                     from => 'guarantor',
1499                     to => 'guarantorid',
1500                     after => 'contactname',
1501                 },
1502                 {
1503                     from => 'altrelationship',
1504                     to => 'relationship',
1505                     after => 'borrowernotes',
1506                 },
1507             ],
1508
1509     deletedborrowers => [
1510                 {
1511                     from => 'emailaddress',
1512                     to => 'email',
1513                     after => 'city',
1514                 },
1515                 {
1516                     from => 'streetaddress',
1517                     to => 'address',
1518                     after => 'initials',
1519                 },
1520                 {
1521                     from => 'faxnumber',
1522                     to => 'fax',
1523                     after => 'phone',
1524                 },
1525                 {
1526                     from => 'textmessaging',
1527                     to => 'opacnote',
1528                     after => 'userid',
1529                 },
1530                 {
1531                     from => 'altnotes',
1532                     to => 'contactnote',
1533                     after => 'opacnote',
1534                 },
1535                 {
1536                     from => 'physstreet',
1537                     to => 'B_address',
1538                     after => 'fax',
1539                 },
1540                 {
1541                     from => 'streetcity',
1542                     to => 'B_city',
1543                     after => 'B_address',
1544                 },
1545                 {
1546                     from => 'phoneday',
1547                     to => 'mobile',
1548                     after => 'phone',
1549                 },
1550                 {
1551                     from => 'zipcode',
1552                     to => 'zipcode',
1553                     after => 'city',
1554                 },
1555                 {
1556                     from => 'homezipcode',
1557                     to => 'B_zipcode',
1558                     after => 'B_city',
1559                 },
1560                 {
1561                     from => 'altphone',
1562                     to => 'B_phone',
1563                     after => 'B_zipcode',
1564                 },
1565                 {
1566                     from => 'expiry',
1567                     to => 'dateexpiry',
1568                     after => 'dateenrolled',
1569                 },
1570                 {
1571                     from => 'guarantor',
1572                     to => 'guarantorid',
1573                     after => 'contactname',
1574                 },
1575                 {
1576                     from => 'altrelationship',
1577                     to => 'relationship',
1578                     after => 'borrowernotes',
1579                 },
1580             ],
1581         );
1582     
1583
1584 # MOVE all tables TO UTF-8 and innoDB
1585 $sth = $dbh->prepare("show table status");
1586 $sth->execute;
1587 while ( my $table = $sth->fetchrow_hashref ) {
1588     next if $table->{Name} eq 'marc_word';
1589     next if $table->{Name} eq 'marc_subfield_table';
1590     next if $table->{Name} eq 'auth_word';
1591     next if $table->{Name} eq 'auth_subfield_table';
1592      if ($table->{Engine} ne 'InnoDB') {
1593          $dbh->do("ALTER TABLE $table->{Name} TYPE = innodb");
1594          print "moving $table->{Name} to InnoDB\n";
1595      }
1596     unless ($table->{Collation} =~ /^utf8/) {
1597          print "moving $table->{Name} to utf8\n";
1598         $dbh->do("ALTER TABLE $table->{Name} CONVERT TO CHARACTER SET utf8");
1599         $dbh->do("ALTER TABLE $table->{Name} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
1600         # FIXME : maybe a ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8 would be better, def char set seems to work fine. If any problem encountered, let's try with convert !
1601     } else {
1602     }
1603 }
1604
1605
1606 foreach my $table (keys %column_change) {
1607     $sth = $dbh->prepare("show columns from $table");
1608     $sth->execute();
1609     undef %types;
1610     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1611     {
1612         $types{$column}->{type} ="$type";
1613         $types{$column}->{null} = "$null";
1614         $types{$column}->{key} = "$key";
1615         $types{$column}->{default} = "$default";
1616         $types{$column}->{extra} = "$extra";
1617     }    # while
1618     my $tablerows = $column_change{$table};
1619     foreach my $row ( @$tablerows ) {
1620         if ($types{$row->{from}}->{type}) {
1621             print "altering $table $row->{from} to $row->{to}\n";
1622             # ALTER TABLE `borrowers` CHANGE `faxnumber` `fax` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
1623 #             alter table `borrowers` change `faxnumber` `fax` type text  null after phone
1624             my $sql =
1625                 "alter table `$table` change `$row->{from}` `$row->{to}` $types{$row->{from}}->{type} ".
1626                 ($types{$row->{from}}->{null} eq 'YES'?" NULL":" NOT NULL").
1627                 ($types{$row->{from}}->{default}?" default ".$types{$row->{from}}->{default}:"").
1628                 "$types{$row->{from}}->{extra} after $row->{after} ";
1629 #             print "$sql";
1630             $dbh->do($sql);
1631         }
1632     }
1633 }
1634
1635 # Enter here the field you want to delete from DB.
1636 # FIXME :: there is a %uselessfield before which seems doing the same things.
1637 my %fieldtodelete = (
1638     # tablename => [fieldname1,fieldname2,...]
1639
1640 ); # %fielddelete
1641
1642 print "removing some unused fields...\n";
1643 foreach my $table ( keys %fieldtodelete ) {
1644     foreach my $field ( @{$fieldtodelete{$table}} ){
1645         print "removing ".$field." from ".$table;
1646         my $sth = $dbh->prepare("ALTER TABLE $table DROP $field");
1647         $sth->execute;
1648         if ( $sth->err ) {
1649             print "Error : $sth->errstr \n";
1650         }
1651     }
1652 }
1653
1654 # Enter here the line you want to remove from DB.
1655 my %linetodelete = (
1656     # table name => where clause.
1657     userflags => "bit = 8", # delete the 'reserveforself' flags
1658     
1659 ); # %linetodelete
1660
1661 #-------------------
1662 # Initialize
1663
1664 # Start checking
1665
1666 # Get version of MySQL database engine.
1667 my $mysqlversion = `mysqld --version`;
1668 $mysqlversion =~ /Ver (\S*) /;
1669 $mysqlversion = $1;
1670 if ( $mysqlversion ge '3.23' ) {
1671     print "Could convert to MyISAM database tables...\n" unless $silent;
1672 }
1673
1674 #---------------------------------
1675 # Tables
1676
1677 # Collect all tables into a list
1678 $sth = $dbh->prepare("show tables");
1679 $sth->execute;
1680 while ( my ($table) = $sth->fetchrow ) {
1681     $existingtables{$table} = 1;
1682 }
1683
1684
1685 # Now add any missing tables
1686 foreach $table ( keys %requiretables ) {
1687     unless ( $existingtables{$table} ) {
1688     print "Adding $table table...\n" unless $silent;
1689         my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1690         $sth->execute;
1691         if ( $sth->err ) {
1692             print "Error : $sth->errstr \n";
1693             $sth->finish;
1694         }    # if error
1695     }    # unless exists
1696 }    # foreach
1697
1698 #---------------------------------
1699 # Columns
1700
1701 foreach $table ( keys %requirefields ) {
1702     print "Check table $table\n" if $debug and not $silent;
1703     $sth = $dbh->prepare("show columns from $table");
1704     $sth->execute();
1705     undef %types;
1706     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1707     {
1708         $types{$column} = $type;
1709     }    # while
1710     foreach $column ( keys %{ $requirefields{$table} } ) {
1711         print "  Check column $column  [$types{$column}]\n" if $debug and not $silent;
1712         if ( !$types{$column} ) {
1713
1714             # column doesn't exist
1715             print "Adding $column field to $table table...\n" unless $silent;
1716             $query = "alter table $table
1717             add column $column " . $requirefields{$table}->{$column};
1718             print "Execute: $query\n" if $debug;
1719             my $sti = $dbh->prepare($query);
1720             $sti->execute;
1721             if ( $sti->err ) {
1722                 print "**Error : $sti->errstr \n";
1723                 $sti->finish;
1724             }    # if error
1725         }    # if column
1726     }    # foreach column
1727 }    # foreach table
1728
1729 foreach $table ( keys %fielddefinitions ) {
1730     print "Check table $table\n" if $debug;
1731     $sth = $dbh->prepare("show columns from $table");
1732     $sth->execute();
1733     my $definitions;
1734     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1735     {
1736         $definitions->{$column}->{type}    = $type;
1737         $definitions->{$column}->{null}    = $null;
1738         $definitions->{$column}->{null}    = 'NULL' if $null eq 'YES';
1739         $definitions->{$column}->{key}     = $key;
1740         $definitions->{$column}->{default} = $default;
1741         $definitions->{$column}->{extra}   = $extra;
1742     }    # while
1743     my $fieldrow = $fielddefinitions{$table};
1744     foreach my $row (@$fieldrow) {
1745         my $field   = $row->{field};
1746         my $type    = $row->{type};
1747         my $null    = $row->{null};
1748 #         $null    = 'YES' if $row->{null} eq 'NULL';
1749         my $key     = $row->{key};
1750         my $default = $row->{default};
1751 #         $default="''" unless $default;
1752         my $extra   = $row->{extra};
1753         my $def     = $definitions->{$field};
1754         my $after    = ($row->{after}?" after ".$row->{after}:"");
1755
1756         unless ( $type eq $def->{type}
1757             && $null eq $def->{null}
1758             && $key eq $def->{key}
1759             && $extra eq $def->{extra} )
1760         {
1761             if ( $null eq '' ) {
1762                 $null = 'NOT NULL';
1763             }
1764             if ( $key eq 'PRI' ) {
1765                 $key = 'PRIMARY KEY';
1766             }
1767             unless ( $extra eq 'auto_increment' ) {
1768                 $extra = '';
1769             }
1770     
1771             # if it's a new column use "add", if it's an old one, use "change".
1772             my $action;
1773             if ($definitions->{$field}->{type}) {
1774                 $action="change $field"
1775             } else {
1776                 $action="add";
1777             }
1778 # if it's a primary key, drop the previous pk, before altering the table
1779             print "  alter or create $field in $table\n" unless $silent;
1780             my $query;
1781             if ($key ne 'PRIMARY KEY') {
1782 #                 warn "alter table $table $action $field $type $null $key $extra default $default $after";
1783                 $query = "alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1784             } else {
1785 #             warn "alter table $table drop primary key, $action $field $type $null $key $extra default $default $after";
1786                  # something strange : for indexes UNIQUE, they are reported as primary key here.
1787                  # but if you try to run with drop primary key, it fails.
1788                  # thus, we run the query twice, one will fail, one will succeed.
1789                  # strange...
1790                 $query="alter table $table drop primary key, $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1791                 $query="alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1792             }
1793             $dbh->do($query);
1794         }
1795     }
1796 }
1797
1798 print "removing some unused data...\n";
1799 foreach my $table ( keys %linetodelete ) {
1800     foreach my $where ( @{linetodelete{$table}} ){
1801         print "DELETE FROM ".$table." where ".$where;
1802         print "\n";
1803         my $sth = $dbh->prepare("DELETE FROM $table where $where");
1804         $sth->execute;
1805         if ( $sth->err ) {
1806             print "Error : $sth->errstr \n";
1807         }
1808     }
1809 }
1810
1811 # Populate tables with required data
1812
1813 # synch table and deletedtable.
1814 foreach my $table (('borrowers','items','biblio','biblioitems')) {
1815     my %deletedborrowers;
1816     print "synch'ing $table and deleted$table\n";
1817     $sth = $dbh->prepare("show columns from deleted$table");
1818     $sth->execute;
1819     while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1820         $deletedborrowers{$column}=1;
1821     }
1822     $sth = $dbh->prepare("show columns from $table");
1823     $sth->execute;
1824     my $previous;
1825     while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1826         unless ($deletedborrowers{$column}) {
1827             my $newcol="alter table deleted$table add $column $type";
1828             if ($null eq 'YES') {
1829                 $newcol .= " NULL ";
1830             } else {
1831                 $newcol .= " NOT NULL ";
1832             }
1833             $newcol .= "default ".$dbh->quote($default) if $default;
1834             $newcol .= " after $previous" if $previous;
1835             $previous=$column;
1836             print "creating column $column\n";
1837             $dbh->do($newcol);
1838         }
1839     }
1840 }
1841 #
1842 # update publisheddate 
1843 #
1844 $sth = $dbh->prepare("select count(*) from serial where publisheddate is NULL");
1845 $sth->execute;
1846 my ($emptypublished) = $sth->fetchrow;
1847 if ($emptypublished) {
1848     print "Updating publisheddate\n";
1849     $dbh->do("update serial set publisheddate=planneddate where publisheddate is NULL");
1850 }
1851 foreach my $table ( keys %tabledata ) {
1852     print "Checking for data required in table $table...\n" unless $silent;
1853     my $tablerows = $tabledata{$table};
1854     foreach my $row (@$tablerows) {
1855         my $uniquefieldrequired = $row->{uniquefieldrequired};
1856         my $uniquevalue         = $row->{$uniquefieldrequired};
1857         my $forceupdate         = $row->{forceupdate};
1858         my $sth                 =
1859           $dbh->prepare(
1860 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1861         );
1862         $sth->execute($uniquevalue);
1863         if ($sth->rows) {
1864             foreach my $field (keys %$forceupdate) {
1865                 if ($forceupdate->{$field}) {
1866                     my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1867                     $sth->execute($row->{$field}, $uniquevalue);
1868                 }
1869             }
1870         } else {
1871             print "Adding row to $table: " unless $silent;
1872             my @values;
1873             my $fieldlist;
1874             my $placeholders;
1875             foreach my $field ( keys %$row ) {
1876                 next if $field eq 'uniquefieldrequired';
1877                 next if $field eq 'forceupdate';
1878                 my $value = $row->{$field};
1879                 push @values, $value;
1880                 print "  $field => $value" unless $silent;
1881                 $fieldlist .= "$field,";
1882                 $placeholders .= "?,";
1883             }
1884             print "\n" unless $silent;
1885             $fieldlist    =~ s/,$//;
1886             $placeholders =~ s/,$//;
1887             print "insert into $table ($fieldlist) values ($placeholders)";
1888             my $sth =
1889             $dbh->prepare(
1890                 "insert into $table ($fieldlist) values ($placeholders)");
1891             $sth->execute(@values);
1892         }
1893     }
1894 }
1895
1896 #
1897 # check indexes and create them when needed
1898 #
1899 print "Checking for index required...\n" unless $silent;
1900 foreach my $table ( keys %indexes ) {
1901     #
1902     # read all indexes from $table
1903     #
1904     $sth = $dbh->prepare("show index from $table");
1905     $sth->execute;
1906     my %existingindexes;
1907     while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow ) {
1908         $existingindexes{$key_name} = 1;
1909     }
1910     # read indexes to check
1911     my $tablerows = $indexes{$table};
1912     foreach my $row (@$tablerows) {
1913         my $key_name=$row->{indexname};
1914         if ($existingindexes{$key_name} eq 1) {
1915 #             print "$key_name existing";
1916         } else {
1917             print "\tCreating index $key_name in $table\n";
1918             my $sql;
1919             if ($row->{indexname} eq 'PRIMARY') {
1920                 $sql = "alter table $table ADD PRIMARY KEY ($row->{content})";
1921             } else {
1922                 $sql = "alter table $table ADD INDEX $key_name ($row->{content}) $row->{type}";
1923             }
1924              $dbh->do($sql);
1925             print "Error $sql : $dbh->err \n" if $dbh->err;
1926         }
1927     }
1928 }
1929
1930 #
1931 # check foreign keys and create them when needed
1932 #
1933 print "Checking for foreign keys required...\n" unless $silent;
1934 foreach my $table ( keys %foreign_keys ) {
1935     #
1936     # read all indexes from $table
1937     #
1938     $sth = $dbh->prepare("show table status like '$table'");
1939     $sth->execute;
1940     my $stat = $sth->fetchrow_hashref;
1941     # read indexes to check
1942     my $tablerows = $foreign_keys{$table};
1943     foreach my $row (@$tablerows) {
1944         my $foreign_table=$row->{foreigntable};
1945         if ($stat->{'Comment'} =~/$foreign_table/) {
1946 #             print "$foreign_table existing\n";
1947         } else {
1948             print "\tCreating foreign key $foreign_table in $table\n";
1949             # first, drop any orphan value in child table
1950             if ($row->{onDelete} ne "RESTRICT") {
1951                 my $sql = "delete from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})";
1952                 $dbh->do($sql);
1953                 print "SQL ERROR: $sql : $dbh->err \n" if $dbh->err;
1954             }
1955             my $sql="alter table $table ADD FOREIGN KEY $row->{key} ($row->{key}) REFERENCES $row->{foreigntable} ($row->{foreignkey})";
1956             $sql .= " on update ".$row->{onUpdate} if $row->{onUpdate};
1957             $sql .= " on delete ".$row->{onDelete} if $row->{onDelete};
1958             $dbh->do($sql);
1959             if ($dbh->err) {
1960                 print "====================
1961 An error occured during :
1962 \t$sql
1963 It probably means there is something wrong in your DB : a row ($table.$row->{key}) refers to a value in $row->{foreigntable}.$row->{foreignkey} that does not exist. solve the problem and run updater again (or just the previous SQL statement).
1964 You can find those values with select
1965 \t$table.* from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})
1966 ====================\n
1967 ";
1968             }
1969         }
1970     }
1971 }
1972 # now drop useless tables
1973 foreach $table ( @TableToDelete ) {
1974     if ( $existingtables{$table} ) {
1975         print "Dropping unused table $table\n" if $debug and not $silent;
1976         $dbh->do("drop table $table");
1977         if ( $dbh->err ) {
1978             print "Error : $dbh->errstr \n";
1979         }
1980     }
1981 }
1982
1983 #
1984 # SPECIFIC STUFF
1985 #
1986 #
1987 # create frameworkcode row in biblio table & fill it with marc_biblio.frameworkcode.
1988 #
1989
1990 # 1st, get how many biblio we will have to do...
1991 $sth = $dbh->prepare('select count(*) from marc_biblio');
1992 $sth->execute;
1993 my ($totaltodo) = $sth->fetchrow;
1994
1995 $sth = $dbh->prepare("show columns from biblio");
1996 $sth->execute();
1997 my $definitions;
1998 my $bibliofwexist=0;
1999 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
2000     $bibliofwexist=1 if $column eq 'frameworkcode';
2001 }
2002 unless ($bibliofwexist) {
2003     print "moving biblioframework to biblio table\n";
2004     $dbh->do('ALTER TABLE `biblio` ADD `frameworkcode` VARCHAR( 4 ) NOT NULL AFTER `biblionumber`');
2005     $sth = $dbh->prepare('select biblionumber,frameworkcode from marc_biblio');
2006     $sth->execute;
2007     my $sth_update = $dbh->prepare('update biblio set frameworkcode=? where biblionumber=?');
2008     my $totaldone=0;
2009     while (my ($biblionumber,$frameworkcode) = $sth->fetchrow) {
2010         $sth_update->execute($frameworkcode,$biblionumber);
2011         $totaldone++;
2012         print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
2013     }
2014     print "\rdone\n";
2015 }
2016
2017 # at last, remove useless fields
2018 foreach $table ( keys %uselessfields ) {
2019     my @fields = split /,/,$uselessfields{$table};
2020     my $fields;
2021     my $exists;
2022     foreach my $fieldtodrop (@fields) {
2023         $fieldtodrop =~ s/\t//g;
2024         $fieldtodrop =~ s/\n//g;
2025         $exists =0;
2026         $sth = $dbh->prepare("show columns from $table");
2027         $sth->execute;
2028         while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
2029         {
2030             $exists =1 if ($column eq $fieldtodrop);
2031         }
2032         if ($exists) {
2033             print "deleting $fieldtodrop field in $table...\n" unless $silent;
2034             my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
2035             $sth->execute;
2036         }
2037     }
2038 }    # foreach
2039
2040 #
2041 # Changing aqbookfund's primary key 
2042 #
2043 $sth=$dbh->prepare("ALTER TABLE `aqbookfund` DROP PRIMARY KEY , ADD PRIMARY KEY ( `bookfundid` , `branchcode` ) ;");
2044 $sth->execute;
2045
2046 $sth->finish;
2047
2048 exit;
2049
2050 # $Log$
2051 # Revision 1.170  2007/06/26 13:25:37  tipaul
2052 # removing some useless tables from updatedatabase
2053 #
2054 # Revision 1.169  2007/06/26 09:23:26  tipaul
2055 # improving OpacBrowser systempref explanation
2056 #
2057 # Revision 1.168  2007/06/25 15:02:31  tipaul
2058 # missing field declaration
2059 #
2060 # Revision 1.167  2007/06/15 13:09:08  toins
2061 # bugfix : bibliotitems.dewey & deletedbiblioitems.dewey mustn't be double(8,6).
2062 #
2063 # Revision 1.166  2007/06/08 09:40:12  toins
2064 # bug fix : items.homebranch must be VARCHAR(10)
2065 #
2066 # Revision 1.165  2007/05/23 16:33:10  tipaul
2067 # skip move to innoDB for the 4 22 tables, that are used to store MARC records, are useless in Koha 3.0 The process is very very long, so the updatedatabase should speed up a lot (by long I mean 1 hour on my Dual core with SCSI disk, for a 50 000 biblios long table
2068 #
2069 # Revision 1.164  2007/05/04 16:24:09  tipaul
2070 # various bugfixes on parameters modules + adding default NoZebraIndexes systempreference if it's empty
2071 #
2072 # Revision 1.163  2007/05/02 16:44:31  tipaul
2073 # NoZebra SQL index management :
2074 # * adding 3 subs in Biblio.pm
2075 # - GetNoZebraIndexes, that get the index structure in a new systempreference (added with this commit)
2076 # - _DelBiblioNoZebra, that retrieve all index entries for a biblio and remove in a variable the biblio reference
2077 # - _AddBiblioNoZebra, that add index entries for a biblio.
2078 # Note that the 2 _Add and _Del subs work only in a hash variable, to speed up things in case of a modif (ie : delete+add). The effective SQL update is done in the ModZebra sub (that existed before, and dealed with zebra index).
2079 # I think the code has to be more deeply tested, but it works at least partially.
2080 #
2081 # Revision 1.162  2007/04/30 16:16:50  tipaul
2082 # bugfix for updatedatabase : when there is no default value (NULL fields) + removing bibliothesaurus table+adding NoZebra systempref (False by default)
2083 #
2084 # Revision 1.161  2007/04/13 16:27:55  hdl
2085 # Adding Version variable to systempreferences.
2086 #
2087 # Revision 1.160  2007/03/19 18:35:13  toins
2088 #  - adding default value in marc_subfield_structure.
2089 #  - now marc_subfields_structure displays subfields in tab view.
2090 #
2091 # Revision 1.159  2007/03/16 01:25:09  kados
2092 # Using my precrash CVS copy I did the following:
2093 #
2094 # cvs -z3 -d:ext:kados@cvs.savannah.nongnu.org:/sources/koha co -P koha
2095 # find koha.precrash -type d -name "CVS" -exec rm -v {} \;
2096 # cp -r koha.precrash/* koha/
2097 # cd koha/
2098 # cvs commit
2099 #
2100 # This should in theory put us right back where we were before the crash
2101 #
2102 # Revision 1.159  2007/03/12 17:52:30  rych
2103 # add pri key to userflags
2104 #
2105 # Revision 1.158  2007/03/09 15:14:57  tipaul
2106 # rel_3_0 moved to HEAD
2107 #
2108 # Revision 1.157.2.56  2007/01/31 16:22:54  btoumi
2109 # -add possibility to use isbn with length of 13 characters
2110 # for  Import datas in the reservoir.
2111 # -modify isbn field in marc_breeding table (varchar 13)
2112 # -add isbn filter (no - )when u read a notice from reservoir
2113 # -add filter to have right field 100
2114 #
2115 # Revision 1.157.2.55  2007/01/30 10:50:19  tipaul
2116 # adding 2 usefull indexes to biblioitems table
2117 #
2118 # Revision 1.157.2.54  2007/01/29 16:45:52  toins
2119 # * adding a new default authorised value : SUGGEST.
2120 # SUGGEST give some reasons to accept or reject a suggestion.
2121 #
2122 # * default value for borrowersMandatoryfield syspref is now "cardnumber|surname|adress"
2123 #
2124 # Revision 1.157.2.53  2007/01/26 20:48:37  hdl
2125 # Serials management : Bugfixes + improvements.
2126 # - Partial dates are now managed
2127 # - next Date Calculation with irregularity tested for 1 week and 1 month.
2128 # - manage if subscription is abouttoexpire or expired.
2129 # - Adding some information on serials pages about subscription.
2130 # - Managing irregularity with numbers.
2131 # - Adding Internal Notes in subscription management.
2132 # - Repeating Button above pages.
2133 #
2134 # Please run Updatedatabase to change irregularity and add internalnotes field  to subscription
2135 #
2136 # Revision 1.157.2.52  2007/01/24 13:57:26  tipaul
2137 # - setting supplierid to auto_increment (HDL : could you check that is works, i'm not 100% sure)
2138 # - removing 22 -> 30 marc_subfield_table -> marcxml stuff, it's now in misc/migration_tools/22_to_30/
2139 #
2140 # Revision 1.157.2.51  2007/01/18 09:58:45  tipaul
2141 # defaulting NOT NULL fields (to '')
2142 #
2143 # Revision 1.157.2.50  2007/01/18 09:39:21  tipaul
2144 # issuedate must be defaulted with ' '
2145 #
2146 # Revision 1.157.2.49  2007/01/18 09:37:30  tipaul
2147 # removing 2 field definitions that were here twice
2148 #
2149 # Revision 1.157.2.48  2007/01/15 09:55:40  toins
2150 # adding a new logging systempref : FinesLog.
2151 #
2152 # Revision 1.157.2.47  2007/01/12 18:09:49  toins
2153 # LetterLog added
2154 #
2155 # Revision 1.157.2.46  2007/01/11 14:35:39  tipaul
2156 # adding Opac Browser feature : the build_browser_and_cloud.pl script will :
2157 # - fill the browser table, that enable browsing, digit by digit of a given category, the catalogue. A complete dewey classification is provided in the script, active only for french libraries, of course (although, for instance, the script check that the catalogue is in english for developping convenience)
2158 # - fill the tags table, that contains the subject cloud.
2159 #
2160 # The cloud part is a copy of the previous build_tags.pl script that can be deleted : those 2 scripts require to parse all the catalogue to extract interesting data, so they are long. It's useless to parse the catalogue twice !
2161 #
2162 # The commit also add the systempreference to hide/show the OpacBrowse in database & in systempref management script.
2163 #
2164 # IMPROVEMENTS to do :
2165 # - the script that builds the tables can be improved to update only last week biblios (at the price of a small error in value links, but it's not a problem).
2166 # - add, in parameters section, a place to edit browser descriptions. The build script has to be updated to to avoid deleting existing browser descriptions.
2167 #
2168 # Revision 1.157.2.45  2007/01/10 16:52:52  toins
2169 # Value for Log Features syspref are set to 0 by default.
2170 #
2171 # Revision 1.157.2.44  2007/01/10 16:31:15  toins
2172 # new systems preferences :
2173 #  - CataloguingLog (log the update/creation/deletion of a notice if set to 1)
2174 #  - BorrowersLog ( idem for borrowers )
2175 #  - IssueLog (log all issue if set to 1)
2176 #  - ReturnLog (log all return if set to 1)
2177 #  - SusbcriptionLog (log all creation/deletion/update of a subcription)
2178 #
2179 # All of theses are in a new tab called 'LOGFeatures' in systempreferences.pl
2180 #
2181 # Revision 1.157.2.43  2007/01/10 14:13:17  toins
2182 # opac_news.displayed is replaced by opac_news.number.
2183 # This field say how are ordered the news on the template.
2184 #
2185 # Revision 1.157.2.42  2007/01/09 14:09:01  toins
2186 # 2 field added to opac_news.('expirationdate' and 'displayed').