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