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