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