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