bump to 3.00.00.006 : issues.issuedate auto fill added on update
[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    => 'issue_date',
1043                 type    => 'date',
1044                 null    => 'NULL',
1045                 key        => '',
1046                 default    => '',
1047                 extra    => '',
1048             },
1049             {
1050                 field    => 'homebranch',
1051                 type    => 'varchar(10)',
1052                 null    => 'NULL',
1053                 key        => '',
1054                 default    => '',
1055                 extra    => '',
1056             },
1057             {
1058                 field    => 'holdingbranch',
1059                 type    => 'varchar(10)',
1060                 null    => 'NULL',
1061                 key        => '',
1062                 default    => '',
1063                 extra    => '',
1064             },
1065             {
1066                 field    => 'itype',
1067                 type    => 'varchar(10)',
1068                 null    => 'NULL',
1069                 key        => '',
1070                 default    => '',
1071                 extra    => '',
1072             },
1073         ],
1074         itemtypes => [
1075             {
1076                 field  => 'itemtype',
1077                 type   => 'varchar(10)',
1078                 default    => '',
1079                 null   => 'NOT NULL',
1080                 key    => 'PRI',
1081                 extra  => 'UNIQUE',
1082             },
1083             {
1084                 field  => 'summary',
1085                 type   => 'TEXT',
1086                 null   => 'NULL',
1087                 key    => '',
1088                 extra  => '',
1089             },
1090         ],
1091         marc_breeding => [
1092             {
1093                 field => 'marc',
1094                 type  => 'LONGBLOB',
1095                 null  => 'NULL',
1096                 key    => '',
1097                 extra  => '',
1098             }
1099         ],
1100         marc_subfield_structure => [
1101             {
1102                 field => 'defaultvalue',
1103                 type  => 'TEXT',
1104                 null  => 'NULL',
1105                 key    => '',
1106                 extra  => '',
1107             }
1108         ],
1109         opac_news => [
1110             {
1111                 field  => 'expirationdate',
1112                 type   => 'date',
1113                 null   => 'null',
1114                 key    => '',
1115                 extra  => '',
1116             },
1117             {
1118                 field   => 'number',
1119                 type    => 'int(11)',
1120                 null    => 'NULL',
1121                 key     => '',
1122                 default => '0',
1123                 extra   => '',
1124             },
1125         ],
1126         reserves =>  [
1127             {
1128                 field    => 'waitingdate',
1129                 type    => 'date',
1130                 null    => 'NULL',
1131                 key        => '',
1132                 default    => '',
1133                 extra    => '',
1134             },
1135         ],
1136         serial => [
1137             {
1138                 field   => 'notes',
1139                 type    => 'TEXT',
1140                 null    => 'NULL',
1141                 key     => '',
1142                 default => '',
1143                 extra   => ''
1144             },
1145         ],
1146         shelfcontents => [
1147             {
1148                 field => 'dateadded',
1149                 type => 'timestamp',
1150                 null    => 'NULL',
1151             },
1152         ],
1153         systempreferences =>  [
1154             {
1155                 field    => 'value',
1156                 type    => 'text',
1157                 null    => 'NULL',
1158                 key        => '',
1159                 default    => '',
1160                 extra    => '',
1161             },
1162             {
1163                 field    => 'explanation',
1164                 type    => 'text',
1165                 null    => 'NULL',
1166                 key        => '',
1167                 default    => '',
1168                 extra    => '',
1169             },
1170         ],
1171         suggestions => [
1172             {
1173                 field   => 'reason',
1174                 type    => 'text',
1175                 null    => 'NULL',
1176                 key     => ''  ,
1177                 default => '',
1178                 extra   =>    '',
1179             }
1180         ],
1181     );
1182     
1183     my %indexes = (
1184     #    table => [
1185     #         {    indexname => 'index detail'
1186     #         }
1187     #    ],
1188         aqbooksellers => [
1189             {    indexname => 'PRIMARY',
1190                 content => 'id',
1191                 type => 'PRI',
1192             }
1193         ],
1194         aqbasket => [
1195             {    indexname => 'booksellerid',
1196                 content => 'booksellerid',
1197             },
1198         ],
1199         aqorders => [
1200             {    indexname => 'basketno',
1201                 content => 'basketno',
1202             },
1203         ],
1204         aqorderbreakdown => [
1205             {    indexname => 'ordernumber',
1206                 content => 'ordernumber',
1207             },
1208             {    indexname => 'bookfundid',
1209                 content => 'bookfundid',
1210             },
1211         ],
1212         biblioitems => [
1213             {    indexname => 'isbn',
1214                 content => 'isbn',
1215             },
1216             {    indexname => 'publishercode',
1217                 content => 'publishercode',
1218             },
1219         ],
1220         branches => [
1221             {
1222                 indexname => 'branchcode',
1223                 content   => 'branchcode',
1224                 type => 'PRI',
1225             }
1226         ],
1227         branchrelations => [
1228             {
1229                 indexname => 'PRIMARY',
1230                 content => 'categorycode',
1231                 type => 'PRI',
1232             }
1233         ],
1234         branchrelations => [
1235             {    indexname => 'PRIMARY',
1236                 content => 'branchcode,categorycode',
1237                 type => 'PRI',
1238             },
1239             {    indexname => 'branchcode',
1240                 content => 'branchcode',
1241             },
1242             {    indexname => 'categorycode',
1243                 content => 'categorycode',
1244             }
1245         ],
1246         currency => [
1247             {    indexname => 'PRIMARY',
1248                 content => 'currency',
1249                 type => 'PRI',
1250             }
1251         ],
1252         categories => [
1253             {
1254                 indexname => 'categorycode',
1255                 content   => 'categorycode',
1256             }
1257         ],
1258         items => [
1259             {    indexname => 'homebranch',
1260                 content => 'homebranch',
1261             },
1262             {    indexname => 'holdingbranch',
1263                 content => 'holdingbranch',
1264             }
1265         ],
1266         itemtypes => [
1267             {
1268                 indexname => 'itemtype',
1269                 content   => 'itemtype',
1270             }
1271         ],
1272         shelfcontents => [
1273             {    indexname => 'shelfnumber',
1274                 content => 'shelfnumber',
1275             },
1276             {    indexname => 'itemnumber',
1277                 content => 'itemnumber',
1278             }
1279         ],
1280             userflags => [
1281                     {   indexname => 'PRIMARY',
1282                             content => 'bit',
1283                             type => 'PRI',
1284                     }
1285             ]
1286     );
1287     
1288     my %foreign_keys = (
1289     #    table => [
1290     #         {    key => 'the key in table' (must be indexed)
1291     #            foreigntable => 'the foreigntable name', # (the parent)
1292     #            foreignkey => 'the foreign key column(s)' # (in the parent)
1293     #            onUpdate => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1294     #            onDelete => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1295     #         }
1296     #    ],
1297         branchrelations => [
1298             {    key => 'branchcode',
1299                 foreigntable => 'branches',
1300                 foreignkey => 'branchcode',
1301                 onUpdate => 'CASCADE',
1302                 onDelete => 'CASCADE',
1303             },
1304             {    key => 'categorycode',
1305                 foreigntable => 'branchcategories',
1306                 foreignkey => 'categorycode',
1307                 onUpdate => 'CASCADE',
1308                 onDelete => 'CASCADE',
1309             },
1310         ],
1311         shelfcontents => [
1312             {    key => 'shelfnumber',
1313                 foreigntable => 'virtualshelf',
1314                 foreignkey => 'shelfnumber',
1315                 onUpdate => 'CASCADE',
1316                 onDelete => 'CASCADE',
1317             },
1318             {    key => 'itemnumber',
1319                 foreigntable => 'items',
1320                 foreignkey => 'itemnumber',
1321                 onUpdate => 'CASCADE',
1322                 onDelete => 'CASCADE',
1323             },
1324         ],
1325         # onDelete is RESTRICT on reference tables (branches, itemtype) as we don't want items to be
1326         # easily deleted, but branches/itemtype not too easy to empty...
1327         biblioitems => [
1328             {    key => 'biblionumber',
1329                 foreigntable => 'biblio',
1330                 foreignkey => 'biblionumber',
1331                 onUpdate => 'CASCADE',
1332                 onDelete => 'CASCADE',
1333             },
1334             {    key => 'itemtype',
1335                 foreigntable => 'itemtypes',
1336                 foreignkey => 'itemtype',
1337                 onUpdate => 'CASCADE',
1338                 onDelete => 'RESTRICT',
1339             },
1340         ],
1341         items => [
1342             {    key => 'biblioitemnumber',
1343                 foreigntable => 'biblioitems',
1344                 foreignkey => 'biblioitemnumber',
1345                 onUpdate => 'CASCADE',
1346                 onDelete => 'CASCADE',
1347             },
1348             {    key => 'homebranch',
1349                 foreigntable => 'branches',
1350                 foreignkey => 'branchcode',
1351                 onUpdate => 'CASCADE',
1352                 onDelete => 'RESTRICT',
1353             },
1354             {    key => 'holdingbranch',
1355                 foreigntable => 'branches',
1356                 foreignkey => 'branchcode',
1357                 onUpdate => 'CASCADE',
1358                 onDelete => 'RESTRICT',
1359             },
1360         ],
1361         aqbasket => [
1362             {    key => 'booksellerid',
1363                 foreigntable => 'aqbooksellers',
1364                 foreignkey => 'id',
1365                 onUpdate => 'CASCADE',
1366                 onDelete => 'RESTRICT',
1367             },
1368         ],
1369         aqorders => [
1370             {    key => 'basketno',
1371                 foreigntable => 'aqbasket',
1372                 foreignkey => 'basketno',
1373                 onUpdate => 'CASCADE',
1374                 onDelete => 'CASCADE',
1375             },
1376             {    key => 'biblionumber',
1377                 foreigntable => 'biblio',
1378                 foreignkey => 'biblionumber',
1379                 onUpdate => 'SET NULL',
1380                 onDelete => 'SET NULL',
1381             },
1382         ],
1383         aqbooksellers => [
1384             {    key => 'listprice',
1385                 foreigntable => 'currency',
1386                 foreignkey => 'currency',
1387                 onUpdate => 'CASCADE',
1388                 onDelete => 'CASCADE',
1389             },
1390             {    key => 'invoiceprice',
1391                 foreigntable => 'currency',
1392                 foreignkey => 'currency',
1393                 onUpdate => 'CASCADE',
1394                 onDelete => 'CASCADE',
1395             },
1396         ],
1397         aqorderbreakdown => [
1398             {    key => 'ordernumber',
1399                 foreigntable => 'aqorders',
1400                 foreignkey => 'ordernumber',
1401                 onUpdate => 'CASCADE',
1402                 onDelete => 'CASCADE',
1403             },
1404             {    key => 'bookfundid',
1405                 foreigntable => 'aqbookfund',
1406                 foreignkey => 'bookfundid',
1407                 onUpdate => 'CASCADE',
1408                 onDelete => 'CASCADE',
1409             },
1410         ],
1411         branchtransfers => [
1412             {    key => 'frombranch',
1413                 foreigntable => 'branches',
1414                 foreignkey => 'branchcode',
1415                 onUpdate => 'CASCADE',
1416                 onDelete => 'CASCADE',
1417             },
1418             {    key => 'tobranch',
1419                 foreigntable => 'branches',
1420                 foreignkey => 'branchcode',
1421                 onUpdate => 'CASCADE',
1422                 onDelete => 'CASCADE',
1423             },
1424             {    key => 'itemnumber',
1425                 foreigntable => 'items',
1426                 foreignkey => 'itemnumber',
1427                 onUpdate => 'CASCADE',
1428                 onDelete => 'CASCADE',
1429             },
1430         ],
1431         issuingrules => [
1432             {    key => 'categorycode',
1433                 foreigntable => 'categories',
1434                 foreignkey => 'categorycode',
1435                 onUpdate => 'CASCADE',
1436                 onDelete => 'CASCADE',
1437             },
1438             {    key => 'itemtype',
1439                 foreigntable => 'itemtypes',
1440                 foreignkey => 'itemtype',
1441                 onUpdate => 'CASCADE',
1442                 onDelete => 'CASCADE',
1443             },
1444         ],
1445         issues => [    # constraint is SET NULL : when a borrower or an item is deleted, we keep the issuing record
1446         # for stat purposes
1447             {    key => 'borrowernumber',
1448                 foreigntable => 'borrowers',
1449                 foreignkey => 'borrowernumber',
1450                 onUpdate => 'SET NULL',
1451                 onDelete => 'SET NULL',
1452             },
1453             {    key => 'itemnumber',
1454                 foreigntable => 'items',
1455                 foreignkey => 'itemnumber',
1456                 onUpdate => 'SET NULL',
1457                 onDelete => 'SET NULL',
1458             },
1459         ],
1460         reserves => [
1461             {    key => 'borrowernumber',
1462                 foreigntable => 'borrowers',
1463                 foreignkey => 'borrowernumber',
1464                 onUpdate => 'CASCADE',
1465                 onDelete => 'CASCADE',
1466             },
1467             {    key => 'biblionumber',
1468                 foreigntable => 'biblio',
1469                 foreignkey => 'biblionumber',
1470                 onUpdate => 'CASCADE',
1471                 onDelete => 'CASCADE',
1472             },
1473             {    key => 'itemnumber',
1474                 foreigntable => 'items',
1475                 foreignkey => 'itemnumber',
1476                 onUpdate => 'CASCADE',
1477                 onDelete => 'CASCADE',
1478             },
1479             {    key => 'branchcode',
1480                 foreigntable => 'branches',
1481                 foreignkey => 'branchcode',
1482                 onUpdate => 'CASCADE',
1483                 onDelete => 'CASCADE',
1484             },
1485         ],
1486         borrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1487         # but prevent deleting a branch as soon as it has 1 borrower !
1488             {    key => 'categorycode',
1489                 foreigntable => 'categories',
1490                 foreignkey => 'categorycode',
1491                 onUpdate => 'RESTRICT',
1492                 onDelete => 'RESTRICT',
1493             },
1494             {    key => 'branchcode',
1495                 foreigntable => 'branches',
1496                 foreignkey => 'branchcode',
1497                 onUpdate => 'RESTRICT',
1498                 onDelete => 'RESTRICT',
1499             },
1500         ],
1501         deletedborrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1502         # but prevent deleting a branch as soon as it has 1 borrower !
1503             {    key => 'categorycode',
1504                 foreigntable => 'categories',
1505                 foreignkey => 'categorycode',
1506                 onUpdate => 'RESTRICT',
1507                 onDelete => 'RESTRICT',
1508             },
1509             {    key => 'branchcode',
1510                 foreigntable => 'branches',
1511                 foreignkey => 'branchcode',
1512                 onUpdate => 'RESTRICT',
1513                 onDelete => 'RESTRICT',
1514             },
1515         ],
1516         accountlines => [
1517             {    key => 'borrowernumber',
1518                 foreigntable => 'borrowers',
1519                 foreignkey => 'borrowernumber',
1520                 onUpdate => 'CASCADE',
1521                 onDelete => 'CASCADE',
1522             },
1523             {    key => 'itemnumber',
1524                 foreigntable => 'items',
1525                 foreignkey => 'itemnumber',
1526                 onUpdate => 'SET NULL',
1527                 onDelete => 'SET NULL',
1528             },
1529         ],
1530         auth_tag_structure => [
1531             {    key => 'authtypecode',
1532                 foreigntable => 'auth_types',
1533                 foreignkey => 'authtypecode',
1534                 onUpdate => 'CASCADE',
1535                 onDelete => 'CASCADE',
1536             },
1537         ],
1538         # FIXME : don't constraint auth_*_table and auth_word, as they may be replaced by zebra
1539     );
1540     
1541     
1542     # column changes
1543     my %column_change = (
1544         # table
1545         borrowers => [
1546                     {
1547                         from => 'emailaddress',
1548                         to => 'email',
1549                         after => 'city',
1550                     },
1551                     {
1552                         from => 'streetaddress',
1553                         to => 'address',
1554                         after => 'initials',
1555                     },
1556                     {
1557                         from => 'faxnumber',
1558                         to => 'fax',
1559                         after => 'phone',
1560                     },
1561                     {
1562                         from => 'textmessaging',
1563                         to => 'opacnote',
1564                         after => 'userid',
1565                     },
1566                     {
1567                         from => 'altnotes',
1568                         to => 'contactnote',
1569                         after => 'opacnote',
1570                     },
1571                     {
1572                         from => 'physstreet',
1573                         to => 'B_address',
1574                         after => 'fax',
1575                     },
1576                     {
1577                         from => 'streetcity',
1578                         to => 'B_city',
1579                         after => 'B_address',
1580                     },
1581                     {
1582                         from => 'phoneday',
1583                         to => 'mobile',
1584                         after => 'phone',
1585                     },
1586                     {
1587                         from => 'zipcode',
1588                         to => 'zipcode',
1589                         after => 'city',
1590                     },
1591                     {
1592                         from => 'homezipcode',
1593                         to => 'B_zipcode',
1594                         after => 'B_city',
1595                     },
1596                     {
1597                         from => 'altphone',
1598                         to => 'B_phone',
1599                         after => 'B_zipcode',
1600                     },
1601                     {
1602                         from => 'expiry',
1603                         to => 'dateexpiry',
1604                         after => 'dateenrolled',
1605                     },
1606                     {
1607                         from => 'guarantor',
1608                         to => 'guarantorid',
1609                         after => 'contactname',
1610                     },
1611                     {
1612                         from => 'altrelationship',
1613                         to => 'relationship',
1614                         after => 'borrowernotes',
1615                     },
1616                 ],
1617     
1618         deletedborrowers => [
1619                     {
1620                         from => 'emailaddress',
1621                         to => 'email',
1622                         after => 'city',
1623                     },
1624                     {
1625                         from => 'streetaddress',
1626                         to => 'address',
1627                         after => 'initials',
1628                     },
1629                     {
1630                         from => 'faxnumber',
1631                         to => 'fax',
1632                         after => 'phone',
1633                     },
1634                     {
1635                         from => 'textmessaging',
1636                         to => 'opacnote',
1637                         after => 'userid',
1638                     },
1639                     {
1640                         from => 'altnotes',
1641                         to => 'contactnote',
1642                         after => 'opacnote',
1643                     },
1644                     {
1645                         from => 'physstreet',
1646                         to => 'B_address',
1647                         after => 'fax',
1648                     },
1649                     {
1650                         from => 'streetcity',
1651                         to => 'B_city',
1652                         after => 'B_address',
1653                     },
1654                     {
1655                         from => 'phoneday',
1656                         to => 'mobile',
1657                         after => 'phone',
1658                     },
1659                     {
1660                         from => 'zipcode',
1661                         to => 'zipcode',
1662                         after => 'city',
1663                     },
1664                     {
1665                         from => 'homezipcode',
1666                         to => 'B_zipcode',
1667                         after => 'B_city',
1668                     },
1669                     {
1670                         from => 'altphone',
1671                         to => 'B_phone',
1672                         after => 'B_zipcode',
1673                     },
1674                     {
1675                         from => 'expiry',
1676                         to => 'dateexpiry',
1677                         after => 'dateenrolled',
1678                     },
1679                     {
1680                         from => 'guarantor',
1681                         to => 'guarantorid',
1682                         after => 'contactname',
1683                     },
1684                     {
1685                         from => 'altrelationship',
1686                         to => 'relationship',
1687                         after => 'borrowernotes',
1688                     },
1689                 ],
1690             );
1691         
1692     
1693     # MOVE all tables TO UTF-8 and innoDB
1694     $sth = $dbh->prepare("show table status");
1695     $sth->execute;
1696     while ( my $table = $sth->fetchrow_hashref ) {
1697         next if $table->{Name} eq 'marc_word';
1698         next if $table->{Name} eq 'marc_subfield_table';
1699         next if $table->{Name} eq 'auth_word';
1700         next if $table->{Name} eq 'auth_subfield_table';
1701         if ($table->{Engine} ne 'InnoDB') {
1702             print "moving $table->{Name} to InnoDB\n";
1703             $dbh->do("ALTER TABLE $table->{Name} TYPE = innodb");
1704         }
1705         unless ($table->{Collation} =~ /^utf8/) {
1706             print "moving $table->{Name} to utf8\n";
1707             $dbh->do("ALTER TABLE $table->{Name} CONVERT TO CHARACTER SET utf8");
1708             $dbh->do("ALTER TABLE $table->{Name} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
1709             # 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 !
1710         } else {
1711         }
1712     }
1713     
1714     
1715     foreach my $table (keys %column_change) {
1716         $sth = $dbh->prepare("show columns from $table");
1717         $sth->execute();
1718         undef %types;
1719         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1720         {
1721             $types{$column}->{type} ="$type";
1722             $types{$column}->{null} = "$null";
1723             $types{$column}->{key} = "$key";
1724             $types{$column}->{default} = "$default";
1725             $types{$column}->{extra} = "$extra";
1726         }    # while
1727         my $tablerows = $column_change{$table};
1728         foreach my $row ( @$tablerows ) {
1729             if ($types{$row->{from}}->{type}) {
1730                 print "altering $table $row->{from} to $row->{to}\n";
1731                 # ALTER TABLE `borrowers` CHANGE `faxnumber` `fax` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
1732     #             alter table `borrowers` change `faxnumber` `fax` type text  null after phone
1733                 my $sql =
1734                     "alter table `$table` change `$row->{from}` `$row->{to}` $types{$row->{from}}->{type} ".
1735                     ($types{$row->{from}}->{null} eq 'YES'?" NULL":" NOT NULL").
1736                     ($types{$row->{from}}->{default}?" default ".$types{$row->{from}}->{default}:"").
1737                     "$types{$row->{from}}->{extra} after $row->{after} ";
1738     #             print "$sql";
1739                 $dbh->do($sql);
1740             }
1741         }
1742     }
1743     
1744     # Enter here the field you want to delete from DB.
1745     # FIXME :: there is a %uselessfield before which seems doing the same things.
1746     my %fieldtodelete = (
1747         # tablename => [fieldname1,fieldname2,...]
1748     
1749     ); # %fielddelete
1750     
1751     print "removing some unused fields...\n";
1752     foreach my $table ( keys %fieldtodelete ) {
1753         foreach my $field ( @{$fieldtodelete{$table}} ){
1754             print "removing ".$field." from ".$table;
1755             my $sth = $dbh->prepare("ALTER TABLE $table DROP $field");
1756             $sth->execute;
1757             if ( $sth->err ) {
1758                 print "Error : $sth->errstr \n";
1759             }
1760         }
1761     }
1762     
1763     # Enter here the line you want to remove from DB.
1764     my %linetodelete = (
1765         # table name => where clause.
1766         userflags => "bit = 8", # delete the 'reserveforself' flags
1767         
1768     ); # %linetodelete
1769     
1770     #-------------------
1771     # Initialize
1772     
1773     # Start checking
1774     
1775     # Get version of MySQL database engine.
1776     my $mysqlversion = `mysqld --version`;
1777     $mysqlversion =~ /Ver (\S*) /;
1778     $mysqlversion = $1;
1779     if ( $mysqlversion ge '3.23' ) {
1780         print "Could convert to MyISAM database tables...\n" unless $silent;
1781     }
1782     
1783     #---------------------------------
1784     # Tables
1785     
1786     # Collect all tables into a list
1787     $sth = $dbh->prepare("show tables");
1788     $sth->execute;
1789     while ( my ($table) = $sth->fetchrow ) {
1790         $existingtables{$table} = 1;
1791     }
1792     
1793     
1794     # Now add any missing tables
1795     foreach $table ( keys %requiretables ) {
1796         unless ( $existingtables{$table} ) {
1797         print "Adding $table table...\n" unless $silent;
1798             my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1799             $sth->execute;
1800             if ( $sth->err ) {
1801                 print "Error : $sth->errstr \n";
1802                 $sth->finish;
1803             }    # if error
1804         }    # unless exists
1805     }    # foreach
1806     
1807     #---------------------------------
1808     # Columns
1809     
1810     foreach $table ( keys %requirefields ) {
1811         print "Check table $table\n" if $debug and not $silent;
1812         $sth = $dbh->prepare("show columns from $table");
1813         $sth->execute();
1814         undef %types;
1815         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1816         {
1817             $types{$column} = $type;
1818         }    # while
1819         foreach $column ( keys %{ $requirefields{$table} } ) {
1820             print "  Check column $column  [$types{$column}]\n" if $debug and not $silent;
1821             if ( !$types{$column} ) {
1822     
1823                 # column doesn't exist
1824                 print "Adding $column field to $table table...\n" unless $silent;
1825                 $query = "alter table $table
1826                 add column $column " . $requirefields{$table}->{$column};
1827                 print "Execute: $query\n" if $debug;
1828                 my $sti = $dbh->prepare($query);
1829                 $sti->execute;
1830                 if ( $sti->err ) {
1831                     print "**Error : $sti->errstr \n";
1832                     $sti->finish;
1833                 }    # if error
1834             }    # if column
1835         }    # foreach column
1836     }    # foreach table
1837     
1838     foreach $table ( keys %fielddefinitions ) {
1839         print "Check table $table\n" if $debug;
1840         $sth = $dbh->prepare("show columns from $table");
1841         $sth->execute();
1842         my $definitions;
1843         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1844         {
1845             $definitions->{$column}->{type}    = $type;
1846             $definitions->{$column}->{null}    = $null;
1847             $definitions->{$column}->{null}    = 'NULL' if $null eq 'YES';
1848             $definitions->{$column}->{key}     = $key;
1849             $definitions->{$column}->{default} = $default;
1850             $definitions->{$column}->{extra}   = $extra;
1851         }    # while
1852         my $fieldrow = $fielddefinitions{$table};
1853         foreach my $row (@$fieldrow) {
1854             my $field   = $row->{field};
1855             my $type    = $row->{type};
1856             my $null    = $row->{null};
1857     #         $null    = 'YES' if $row->{null} eq 'NULL';
1858             my $key     = $row->{key};
1859             my $default = $row->{default};
1860     #         $default="''" unless $default;
1861             my $extra   = $row->{extra};
1862             my $def     = $definitions->{$field};
1863             my $after    = ($row->{after}?" after ".$row->{after}:"");
1864     
1865             unless ( $type eq $def->{type}
1866                 && $null eq $def->{null}
1867                 && $key eq $def->{key}
1868                 && $extra eq $def->{extra} )
1869             {
1870                 if ( $null eq '' ) {
1871                     $null = 'NOT NULL';
1872                 }
1873                 if ( $key eq 'PRI' ) {
1874                     $key = 'PRIMARY KEY';
1875                 }
1876                 unless ( $extra eq 'auto_increment' ) {
1877                     $extra = '';
1878                 }
1879         
1880                 # if it's a new column use "add", if it's an old one, use "change".
1881                 my $action;
1882                 if ($definitions->{$field}->{type}) {
1883                     $action="change $field"
1884                 } else {
1885                     $action="add";
1886                 }
1887     # if it's a primary key, drop the previous pk, before altering the table
1888                 print "  alter or create $field in $table\n" unless $silent;
1889                 my $query;
1890                 if ($key ne 'PRIMARY KEY') {
1891     #                 warn "alter table $table $action $field $type $null $key $extra default $default $after";
1892                     $query = "alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1893                 } else {
1894     #             warn "alter table $table drop primary key, $action $field $type $null $key $extra default $default $after";
1895                     # something strange : for indexes UNIQUE, they are reported as primary key here.
1896                     # but if you try to run with drop primary key, it fails.
1897                     # thus, we run the query twice, one will fail, one will succeed.
1898                     # strange...
1899                     $query="alter table $table drop primary key, $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1900                     $query="alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1901                 }
1902                 $dbh->do($query);
1903             }
1904         }
1905     }
1906     
1907     print "removing some unused data...\n";
1908     foreach my $table ( keys %linetodelete ) {
1909         foreach my $where ( @{linetodelete{$table}} ){
1910             print "DELETE FROM ".$table." where ".$where;
1911             print "\n";
1912             my $sth = $dbh->prepare("DELETE FROM $table where $where");
1913             $sth->execute;
1914             if ( $sth->err ) {
1915                 print "Error : $sth->errstr \n";
1916             }
1917         }
1918     }
1919     
1920     # Populate tables with required data
1921     
1922     # synch table and deletedtable.
1923     foreach my $table (('borrowers','items','biblio','biblioitems')) {
1924         my %deletedborrowers;
1925         print "synch'ing $table and deleted$table\n";
1926         $sth = $dbh->prepare("show columns from deleted$table");
1927         $sth->execute;
1928         while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1929             $deletedborrowers{$column}=1;
1930         }
1931         $sth = $dbh->prepare("show columns from $table");
1932         $sth->execute;
1933         my $previous;
1934         while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1935             unless ($deletedborrowers{$column}) {
1936                 my $newcol="alter table deleted$table add $column $type";
1937                 if ($null eq 'YES') {
1938                     $newcol .= " NULL ";
1939                 } else {
1940                     $newcol .= " NOT NULL ";
1941                 }
1942                 $newcol .= "default ".$dbh->quote($default) if $default;
1943                 $newcol .= " after $previous" if $previous;
1944                 $previous=$column;
1945                 print "creating column $column\n";
1946                 $dbh->do($newcol);
1947             }
1948         }
1949     }
1950     #
1951     # update publisheddate 
1952     #
1953     $sth = $dbh->prepare("select count(*) from serial where publisheddate is NULL");
1954     $sth->execute;
1955     my ($emptypublished) = $sth->fetchrow;
1956     if ($emptypublished) {
1957         print "Updating publisheddate\n";
1958         $dbh->do("update serial set publisheddate=planneddate where publisheddate is NULL");
1959     }
1960     foreach my $table ( keys %tabledata ) {
1961         print "Checking for data required in table $table...\n" unless $silent;
1962         my $tablerows = $tabledata{$table};
1963         foreach my $row (@$tablerows) {
1964             my $uniquefieldrequired = $row->{uniquefieldrequired};
1965             my $uniquevalue         = $row->{$uniquefieldrequired};
1966             my $forceupdate         = $row->{forceupdate};
1967             my $sth                 =
1968             $dbh->prepare(
1969     "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1970             );
1971             $sth->execute($uniquevalue);
1972             if ($sth->rows) {
1973                 foreach my $field (keys %$forceupdate) {
1974                     if ($forceupdate->{$field}) {
1975                         my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1976                         $sth->execute($row->{$field}, $uniquevalue);
1977                     }
1978                 }
1979             } else {
1980                 print "Adding row to $table: " unless $silent;
1981                 my @values;
1982                 my $fieldlist;
1983                 my $placeholders;
1984                 foreach my $field ( keys %$row ) {
1985                     next if $field eq 'uniquefieldrequired';
1986                     next if $field eq 'forceupdate';
1987                     my $value = $row->{$field};
1988                     push @values, $value;
1989                     print "  $field => $value" unless $silent;
1990                     $fieldlist .= "$field,";
1991                     $placeholders .= "?,";
1992                 }
1993                 print "\n" unless $silent;
1994                 $fieldlist    =~ s/,$//;
1995                 $placeholders =~ s/,$//;
1996                 print "insert into $table ($fieldlist) values ($placeholders)";
1997                 my $sth =
1998                 $dbh->prepare(
1999                     "insert into $table ($fieldlist) values ($placeholders)");
2000                 $sth->execute(@values);
2001             }
2002         }
2003     }
2004     
2005     #
2006     # check indexes and create them when needed
2007     #
2008     print "Checking for index required...\n" unless $silent;
2009     foreach my $table ( keys %indexes ) {
2010         #
2011         # read all indexes from $table
2012         #
2013         $sth = $dbh->prepare("show index from $table");
2014         $sth->execute;
2015         my %existingindexes;
2016         while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow ) {
2017             $existingindexes{$key_name} = 1;
2018         }
2019         # read indexes to check
2020         my $tablerows = $indexes{$table};
2021         foreach my $row (@$tablerows) {
2022             my $key_name=$row->{indexname};
2023             if ($existingindexes{$key_name} eq 1) {
2024     #             print "$key_name existing";
2025             } else {
2026                 print "\tCreating index $key_name in $table\n";
2027                 my $sql;
2028                 if ($row->{indexname} eq 'PRIMARY') {
2029                     $sql = "alter table $table ADD PRIMARY KEY ($row->{content})";
2030                 } else {
2031                     $sql = "alter table $table ADD INDEX $key_name ($row->{content}) $row->{type}";
2032                 }
2033                 $dbh->do($sql);
2034                 print "Error $sql : $dbh->err \n" if $dbh->err;
2035             }
2036         }
2037     }
2038     
2039     #
2040     # check foreign keys and create them when needed
2041     #
2042     print "Checking for foreign keys required...\n" unless $silent;
2043     foreach my $table ( keys %foreign_keys ) {
2044         #
2045         # read all indexes from $table
2046         #
2047         $sth = $dbh->prepare("show table status like '$table'");
2048         $sth->execute;
2049         my $stat = $sth->fetchrow_hashref;
2050         # read indexes to check
2051         my $tablerows = $foreign_keys{$table};
2052         foreach my $row (@$tablerows) {
2053             my $foreign_table=$row->{foreigntable};
2054             if ($stat->{'Comment'} =~/$foreign_table/) {
2055     #             print "$foreign_table existing\n";
2056             } else {
2057                 print "\tCreating foreign key $foreign_table in $table\n";
2058                 # first, drop any orphan value in child table
2059                 if ($row->{onDelete} ne "RESTRICT") {
2060                     my $sql = "delete from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})";
2061                     $dbh->do($sql);
2062                     print "SQL ERROR: $sql : $dbh->err \n" if $dbh->err;
2063                 }
2064                 my $sql="alter table $table ADD FOREIGN KEY $row->{key} ($row->{key}) REFERENCES $row->{foreigntable} ($row->{foreignkey})";
2065                 $sql .= " on update ".$row->{onUpdate} if $row->{onUpdate};
2066                 $sql .= " on delete ".$row->{onDelete} if $row->{onDelete};
2067                 $dbh->do($sql);
2068                 if ($dbh->err) {
2069                     print "====================
2070     An error occured during :
2071     \t$sql
2072     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).
2073     You can find those values with select
2074     \t$table.* from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})
2075     ====================\n
2076     ";
2077                 }
2078             }
2079         }
2080     }
2081     # now drop useless tables
2082     foreach $table ( @TableToDelete ) {
2083         if ( $existingtables{$table} ) {
2084             print "Dropping unused table $table\n" if $debug and not $silent;
2085             $dbh->do("drop table $table");
2086             if ( $dbh->err ) {
2087                 print "Error : $dbh->errstr \n";
2088             }
2089         }
2090     }
2091     
2092     #
2093     # SPECIFIC STUFF
2094     #
2095     #
2096     # create frameworkcode row in biblio table & fill it with marc_biblio.frameworkcode.
2097     #
2098     
2099     # 1st, get how many biblio we will have to do...
2100     $sth = $dbh->prepare('select count(*) from marc_biblio');
2101     $sth->execute;
2102     my ($totaltodo) = $sth->fetchrow;
2103     
2104     $sth = $dbh->prepare("show columns from biblio");
2105     $sth->execute();
2106     my $definitions;
2107     my $bibliofwexist=0;
2108     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
2109         $bibliofwexist=1 if $column eq 'frameworkcode';
2110     }
2111     unless ($bibliofwexist) {
2112         print "moving biblioframework to biblio table\n";
2113         $dbh->do('ALTER TABLE `biblio` ADD `frameworkcode` VARCHAR( 4 ) NOT NULL AFTER `biblionumber`');
2114         $sth = $dbh->prepare('select biblionumber,frameworkcode from marc_biblio');
2115         $sth->execute;
2116         my $sth_update = $dbh->prepare('update biblio set frameworkcode=? where biblionumber=?');
2117         my $totaldone=0;
2118         while (my ($biblionumber,$frameworkcode) = $sth->fetchrow) {
2119             $sth_update->execute($frameworkcode,$biblionumber);
2120             $totaldone++;
2121             print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
2122         }
2123         print "\rdone\n";
2124     }
2125     
2126     # at last, remove useless fields
2127     foreach $table ( keys %uselessfields ) {
2128         my @fields = split /,/,$uselessfields{$table};
2129         my $fields;
2130         my $exists;
2131         foreach my $fieldtodrop (@fields) {
2132             $fieldtodrop =~ s/\t//g;
2133             $fieldtodrop =~ s/\n//g;
2134             $exists =0;
2135             $sth = $dbh->prepare("show columns from $table");
2136             $sth->execute;
2137             while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
2138             {
2139                 $exists =1 if ($column eq $fieldtodrop);
2140             }
2141             if ($exists) {
2142                 print "deleting $fieldtodrop field in $table...\n" unless $silent;
2143                 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
2144                 $sth->execute;
2145             }
2146         }
2147     }    # foreach
2148     
2149     #
2150     # Changing aqbookfund's primary key 
2151     #
2152     $sth=$dbh->prepare("ALTER TABLE `aqbookfund` DROP PRIMARY KEY , ADD PRIMARY KEY ( `bookfundid` , `branchcode` ) ;");
2153     $sth->execute;
2154     
2155     $sth->finish;
2156     print "upgrade to Koha 3.0 done\n";
2157     SetVersion ($DBversion);
2158 } # 3.0000000
2159
2160
2161
2162 =item
2163     Deal with virtualshelves
2164 =cut
2165
2166 $DBversion = "3.00.00.001";
2167 if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
2168     # update virtualshelves table to
2169     # 
2170     $dbh->do("ALTER TABLE `bookshelf` RENAME `virtualshelves`");
2171     $dbh->do("ALTER TABLE `shelfcontents` RENAME `virtualshelfcontents`");
2172     $dbh->do("ALTER TABLE `virtualshelfcontents` ADD `biblionumber` INT( 11 ) NOT NULL");
2173     $dbh->do("UPDATE `virtualshelfcontents` SET biblionumber=(SELECT biblionumber FROM items WHERE items.itemnumber=virtualshelfcontents.itemnumber)");
2174     # drop all foreign keys : otherwise, we can't drop itemnumber field.
2175     DropAllForeignKeys('virtualshelfcontents');
2176     # create the new foreign keys (on biblionumber)
2177     $dbh->do("ALTER TABLE `virtualshelfcontents` ADD FOREIGN KEY biblionumber_fk (biblionumber) REFERENCES biblio (biblionumber) ON UPDATE CASCADE ON DELETE CASCADE");
2178     # re-create the foreign key on virtualshelf
2179     $dbh->do("ALTER TABLE `virtualshelfcontents` ADD FOREIGN KEY shelfnumber_fk (shelfnumber) REFERENCES virtualshelves (shelfnumber) ON UPDATE CASCADE ON DELETE CASCADE");
2180     # now we can drop the itemnumber column
2181     $dbh->do("ALTER TABLE `virtualshelfcontents` DROP `itemnumber`");
2182     print "Upgrade to $DBversion done (virtualshelves)\n";
2183     SetVersion ($DBversion);
2184 }
2185
2186
2187 $DBversion = "3.00.00.002";
2188 if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
2189     $dbh->do("DROP TABLE sessions");
2190     $dbh->do("CREATE TABLE `sessions` (
2191   `id` char(32) NOT NULL,
2192   `a_session` text NOT NULL,
2193   UNIQUE KEY `id` (`id`)
2194 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
2195     print "Upgrade to $DBversion done (sessions uses CGI::session, new table structure for sessions)\n";
2196     SetVersion ($DBversion);
2197 }
2198
2199
2200 $DBversion = "3.00.00.003";
2201 if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
2202     if (C4::Context->preference("opaclanguage") eq "fr") {
2203         $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')");
2204     } else {
2205         $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')");
2206     }
2207     print "Upgrade to $DBversion done (adding ReservesNeedReturns systempref, in circulation)\n";
2208     SetVersion ($DBversion);
2209 }
2210
2211
2212 $DBversion = "3.00.00.004";
2213 if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
2214         $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')");    
2215     print "Upgrade to $DBversion done (adding DebugLevel systempref, in 'Admin' tab)\n";
2216     SetVersion ($DBversion);
2217 }
2218
2219 $DBversion = "3.00.00.005";
2220 if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
2221         $dbh->do("CREATE TABLE `tags` (
2222                     `entry` varchar(255) NOT NULL default '',
2223                     `weight` bigint(20) NOT NULL default 0,
2224                     PRIMARY KEY  (`entry`)
2225                     ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2226                 ");
2227         $dbh->do("CREATE TABLE `nozebra` (
2228                 `server` varchar(20)     NOT NULL,
2229                 `indexname` varchar(40)  NOT NULL,
2230                 `value` varchar(250)     NOT NULL,
2231                 `biblionumbers` longtext NOT NULL,
2232                 KEY `indexname` (`server`,`indexname`),
2233                 KEY `value` (`server`,`value`))
2234                 ENGINE=InnoDB DEFAULT CHARSET=utf8;
2235                 ");
2236     print "Upgrade to $DBversion done (adding tags and nozebra tables )\n";
2237     SetVersion ($DBversion);
2238 }
2239
2240 $DBversion = "3.00.00.006";
2241 if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
2242         $dbh->do("UPDATE issues SET issuedate=timestamp WHERE issuedate='0000-00-00'");
2243     print "Upgrade to $DBversion done (filled issues.issuedate with timestamp)\n";
2244     SetVersion ($DBversion);
2245 }
2246
2247
2248 =item DropAllForeignKeys($table)
2249
2250   Drop all foreign keys of the table $table
2251   
2252 =cut
2253
2254 sub DropAllForeignKeys {
2255     my ($table) = @_;
2256     # get the table description
2257     my $sth = $dbh->prepare("SHOW CREATE TABLE $table");
2258     $sth->execute;
2259     my $vsc_structure = $sth->fetchrow;
2260     # split on CONSTRAINT keyword
2261     my @fks = split /CONSTRAINT /,$vsc_structure;
2262     # parse each entry
2263     foreach (@fks) {
2264         # isolate what is before FOREIGN KEY, if there is something, it's a foreign key to drop
2265         $_ = /(.*) FOREIGN KEY.*/;
2266         my $id = $1;
2267         if ($id) {
2268             # we have found 1 foreign, drop it
2269             $dbh->do("ALTER TABLE $table DROP FOREIGN KEY $id");
2270             $id="";
2271         }
2272     }
2273 }
2274
2275
2276
2277
2278
2279
2280
2281 =item TransformToNum
2282
2283   Transform the Koha version from a 4 parts string
2284   to a number, with just 1 .
2285   
2286 =cut
2287
2288 sub TransformToNum {
2289     my $version = shift;
2290     # remove the 3 last . to have a Perl number
2291     $version =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
2292     return $version;
2293 }
2294
2295 =item SetVersion
2296     set the DBversion in the systempreferences
2297 =cut
2298
2299 sub SetVersion {
2300     my $kohaversion = TransformToNum(shift);
2301     if (C4::Context->preference('Version')) {
2302       my $finish=$dbh->prepare("UPDATE systempreferences SET value=? WHERE variable='Version'");
2303       $finish->execute($kohaversion);
2304     } else {
2305       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')");
2306       $finish->execute($kohaversion);
2307     }
2308 }
2309 exit;
2310
2311 # $Log$
2312 # Revision 1.172  2007/07/19 10:21:22  hdl