6 # This script checks for required updates to the database.
8 # Part of the Koha Library Software www.koha.org
9 # Licensed under the GPL.
12 # - Would also be a good idea to offer to do a backup at this time...
14 # NOTE: If you do something more than once in here, make it table driven.
24 use MARC::File::XML ( BinaryEncoding => 'utf8' );
26 # FIXME - The user might be installing a new database, so can't rely
27 # on /etc/koha.conf anyway.
34 %existingtables, # tables already in database
38 $type, $null, $key, $default, $extra,
39 $prefitem, # preference item in systempreferences table
46 my $dbh = C4::Context->dbh;
47 $|=1; # flushes output
49 my $DBversion = "3.00.00.000";
50 # if we are upgrading from Koha 2.2, then we need to run the complete & long updatedatabase
51 if (C4::Context->preference("Version") < TransformToNum($DBversion) ) {
52 # Tables to add if they don't exist
55 `timestamp` TIMESTAMP NOT NULL ,
56 `user` INT( 11 ) NOT NULL ,
57 `module` TEXT default '',
58 `action` TEXT default '' ,
59 `object` INT(11) NULL ,
60 `info` TEXT default '' ,
61 PRIMARY KEY ( `timestamp` , `user` )
64 module varchar(20) NOT NULL default '',
65 code varchar(20) NOT NULL default '',
66 name varchar(100) NOT NULL default '',
67 title varchar(200) NOT NULL default '',
69 PRIMARY KEY (module,code)
72 alertid int(11) NOT NULL auto_increment,
73 borrowernumber int(11) NOT NULL default '0',
74 type varchar(10) NOT NULL default '',
75 externalid varchar(20) NOT NULL default '',
76 PRIMARY KEY (alertid),
77 KEY borrowernumber (borrowernumber),
78 KEY type (type,externalid)
81 `idnew` int(10) unsigned NOT NULL auto_increment,
82 `title` varchar(250) NOT NULL default '',
84 `lang` varchar(4) NOT NULL default '',
85 `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
88 repeatable_holidays => "(
89 `id` int(11) NOT NULL auto_increment,
90 `branchcode` varchar(4) NOT NULL default '',
91 `weekday` smallint(6) default NULL,
92 `day` smallint(6) default NULL,
93 `month` smallint(6) default NULL,
94 `title` varchar(50) NOT NULL default '',
95 `description` text NOT NULL,
98 special_holidays => "(
99 `id` int(11) NOT NULL auto_increment,
100 `branchcode` varchar(4) NOT NULL default '',
101 `day` smallint(6) NOT NULL default '0',
102 `month` smallint(6) NOT NULL default '0',
103 `year` smallint(6) NOT NULL default '0',
104 `isexception` smallint(1) NOT NULL default '1',
105 `title` varchar(50) NOT NULL default '',
106 `description` text NOT NULL,
109 overduerules =>"(`branchcode` varchar(255) NOT NULL default '',
110 `categorycode` char(2) NOT NULL default '',
111 `delay1` int(4) default '0',
112 `letter1` varchar(20) default NULL,
113 `debarred1` char(1) default '0',
114 `delay2` int(4) default '0',
115 `debarred2` char(1) default '0',
116 `letter2` varchar(20) default NULL,
117 `delay3` int(4) default '0',
118 `letter3` varchar(20) default NULL,
119 `debarred3` int(1) default '0',
120 PRIMARY KEY (`branchcode`,`categorycode`)
122 cities => "(`cityid` int auto_increment,
123 `city_name` char(100) NOT NULL,
124 `city_zipcode` char(20),
125 PRIMARY KEY (`cityid`)
127 roadtype => "(`roadtypeid` int auto_increment,
128 `road_type` char(100) NOT NULL,
129 PRIMARY KEY (`roadtypeid`)
133 labelid int(11) NOT NULL auto_increment,
134 itemnumber varchar(100) NOT NULL default '',
135 timestamp timestamp(14) NOT NULL,
136 PRIMARY KEY (labelid)
140 id int(4) NOT NULL auto_increment,
141 barcodetype char(100) default '',
142 title tinyint(1) default '0',
143 isbn tinyint(1) default '0',
144 itemtype tinyint(1) default '0',
145 barcode tinyint(1) default '0',
146 dewey tinyint(1) default '0',
147 class tinyint(1) default '0',
148 author tinyint(1) default '0',
149 papertype char(100) default '',
150 startrow int(2) default NULL,
154 reviewid integer NOT NULL auto_increment,
155 borrowernumber integer,
156 biblionumber integer,
159 datereviewed datetime,
160 PRIMARY KEY (reviewid)
162 subscriptionroutinglist=>"(
163 routingid integer NOT NULL auto_increment,
164 borrowernumber integer,
166 subscriptionid integer,
167 PRIMARY KEY (routingid)
171 notify_id int(11) NOT NULL default '0',
172 `borrowernumber` int(11) NOT NULL default '0',
173 `itemnumber` int(11) NOT NULL default '0',
174 `notify_date` date NOT NULL default '0000-00-00',
175 `notify_send_date` date default NULL,
176 `notify_level` int(1) NOT NULL default '0',
177 `method` varchar(20) NOT NULL default ''
181 `charge_id` varchar(5) NOT NULL default '',
182 `description` text NOT NULL,
183 `amount` decimal(28,6) NOT NULL default '0.000000',
184 `min` int(4) NOT NULL default '0',
185 `max` int(4) NOT NULL default '0',
186 `level` int(1) NOT NULL default '0',
187 PRIMARY KEY (`charge_id`)
190 `entry` varchar(255) NOT NULL default '',
191 `weight` bigint(20) NOT NULL default '0',
192 PRIMARY KEY (`entry`)
196 `id` int NOT NULL auto_increment,
197 `biblio_auth_number` int NOT NULL,
198 `operation` char(20) NOT NULL,
199 `server` char(20) NOT NULL ,
201 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci AUTO_INCREMENT=1",
205 my %requirefields = (
206 subscription => { 'letter' => 'char(20) NULL', 'distributedto' => 'text NULL', 'firstacquidate'=>'date NOT NULL','irregularity'=>'TEXT NULL default \'\'','numberpattern'=>'TINYINT(3) NULL default 0', 'callnumber'=>'text NULL', 'hemisphere' =>'TINYINT(3) NULL default 0', 'issuesatonce'=>'TINYINT(3) NOT NULL default 1', 'branchcode' =>'varchar(12) NOT NULL default \'\'', 'manualhistory'=>'TINYINT(1) NOT NULL default 0','internalnotes'=>'LONGTEXT NULL default \'\''},
207 itemtypes => { 'imageurl' => 'char(200) NULL'},
208 aqbookfund => { 'branchcode' => 'varchar(4) NULL'},
209 aqbudget => { 'branchcode' => 'varchar(4) NULL'},
210 auth_header => { 'marc' => 'BLOB NOT NULL', 'linkid' => 'BIGINT(20) NULL'},
211 auth_subfield_structure =>{ 'hidden' => 'TINYINT(3) NOT NULL default 0', 'kohafield' => 'VARCHAR(45) NOT NULL', 'linkid' => 'TINYINT(1) NOT NULL default 0', 'isurl' => 'TINYINT(1)', 'frameworkcode'=>'VARCHAR(8) NOT NULL'},
212 marc_breeding => { 'isbn' => 'varchar(13) NOT NULL'},
213 serial =>{ 'publisheddate' => 'date', 'claimdate' => 'date', 'itemnumber'=>'text NULL','routingnotes'=>'text NULL',},
214 statistics => { 'associatedborrower' => 'integer'},
215 z3950servers =>{ "name" =>"text", "description" => "text NOT NULL",
216 "position" =>"enum('primary','secondary','') NOT NULL default 'primary'", "icon" =>"text",
217 "type" =>"enum('zed','opensearch') NOT NULL default 'zed'",
219 issues =>{ 'issuedate'=>"date NOT NULL default '0000-00-00'", },
221 # tablename => { 'field' => 'fieldtype' },
224 # Enter here the table to delete.
225 my @TableToDelete = qw(
232 my %uselessfields = (
233 # tablename => "field1,field2",
234 borrowers => "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
235 deletedborrowers=> "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
237 # the other hash contains other actions that can't be done elsewhere. they are done
238 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
240 # The tabledata hash contains data that should be in the tables.
241 # The uniquefieldrequired hash entry is used to determine which (if any) fields
242 # must not exist in the table for this row to be inserted. If the
243 # uniquefieldrequired entry is already in the table, the existing data is not
244 # modified, unless the forceupdate hash entry is also set. Fields in the
245 # anonymous "forceupdate" hash will be forced to be updated to the default
246 # values given in the %tabledata hash.
250 # { uniquefielrequired => 'fieldname', # the primary key in the table
251 # fieldname => fieldvalue,
252 # fieldname2 => fieldvalue2,
255 systempreferences => [
257 uniquefieldrequired => 'variable',
258 variable => 'useDaysMode',
260 forceupdate => { 'explanation' => 1,
262 explanation => 'How to calculate return dates : Calendar means holidays will be controled, Days means the return date don\'t depend on holidays',
264 options => 'Calendar|Days'
267 uniquefieldrequired => 'variable',
268 variable => 'BorrowersTitles',
269 value => 'Mr|Mrs|Miss|Ms',
270 forceupdate => { 'explanation' => 1,
272 explanation => 'List all Titles for borrowers',
276 uniquefieldrequired => 'variable',
277 variable => 'BorrowerMandatoryField',
278 value => 'cardnumber|surname|address',
279 forceupdate => { 'explanation' => 1,
281 explanation => 'List all mandatory fields for borrowers',
285 uniquefieldrequired => 'variable',
286 variable => 'borrowerRelationship',
287 value => 'father|mother,grand-mother',
288 forceupdate => { 'explanation' => 1,
290 explanation => 'The relationships between a guarantor & a guarantee (separated by | or ,)',
294 uniquefieldrequired => 'variable',
295 variable => 'ReservesMaxPickUpDelay',
297 forceupdate => { 'explanation' => 1,
299 explanation => 'Maximum delay to pick up a reserved document',
303 uniquefieldrequired => 'variable',
304 variable => 'TransfersMaxDaysWarning',
306 forceupdate => { 'explanation' => 1,
308 explanation => 'Max delay before considering the transfer has potentialy a problem',
312 uniquefieldrequired => 'variable',
313 variable => 'memberofinstitution',
315 forceupdate => { 'explanation' => 1,
317 explanation => 'Are your patrons members of institutions',
321 uniquefieldrequired => 'variable',
322 variable => 'ReadingHistory',
324 forceupdate => { 'explanation' => 1,
326 explanation => 'Allow reading record info retrievable from issues and oldissues tables',
330 uniquefieldrequired => 'variable',
331 variable => 'IssuingInProcess',
333 forceupdate => { 'explanation' => 1,
335 explanation => 'Allow no debt alert if the patron is issuing item that accumulate debt',
339 uniquefieldrequired => 'variable',
340 variable => 'AutomaticItemReturn',
342 forceupdate => { 'explanation' => 1,
344 explanation => 'This Variable allow or not to return automaticly to his homebranch',
348 uniquefieldrequired => 'variable',
349 variable => 'reviewson',
351 forceupdate => { 'explanation' => 1,
353 explanation => 'Allows patrons to submit reviews from the opac',
357 uniquefieldrequired => 'variable',
358 variable => 'intranet_includes',
360 forceupdate => { 'explanation' => 1,
362 explanation => 'The includes directory you want for specific look of Koha (includes or includes_npl for example)',
366 uniquefieldrequired => 'variable',
367 variable => 'AutoLocation',
369 forceupdate => { 'explanation' => 1,
371 explanation => 'switch to activate or not Autolocation, if Yes, the Librarian can\'t change his location, it\'s defined by branchip',
375 uniquefieldrequired => 'variable',
376 variable => 'serialsadditems',
382 explanation => 'If set, a new item will be automatically added when receiving an issue',
386 uniquefieldrequired => 'variable',
387 variable => 'expandedSearchOption',
393 explanation => 'search among marc field',
397 uniquefieldrequired => 'variable',
398 variable => 'RequestOnOpac',
400 forceupdate => { 'explanation' => 1,
402 explanation => 'option to allow reserves on opac',
406 uniquefieldrequired => 'variable',
407 variable => 'OpacCloud',
409 forceupdate => { 'explanation' => 1,
411 explanation => 'Enable / Disable cloud link on OPAC (Require to run misc/cronjobs/build_browser_and_cloud.pl on the server)',
415 uniquefieldrequired => 'variable',
416 variable => 'OpacBrowser',
418 forceupdate => { 'explanation' => 1,
420 explanation => 'Enable/Disable browser link on OPAC (Require to run misc/cronjobs/build_browser_and_cloud.pl on the server)',
424 uniquefieldrequired => 'variable',
425 variable => 'OpacTopissue',
427 forceupdate => { 'explanation' => 1,
429 explanation => 'Enable / Disable the top issue link on OPAC',
433 uniquefieldrequired => 'variable',
434 variable => 'OpacAuthorities',
436 forceupdate => { 'explanation' => 1,
438 explanation => 'Enable / Disable the search authority link on OPAC',
442 uniquefieldrequired => 'variable',
443 variable => 'CataloguingLog',
445 forceupdate => {'explanation' => 1, 'type' => 1},
446 explanation => 'Active this if you want to log cataloguing action.',
450 uniquefieldrequired => 'variable',
451 variable => 'BorrowersLog',
453 forceupdate => {'explanation' => 1, 'type' => 1},
454 explanation => 'Active this if you want to log borrowers edition/creation/deletion...',
458 uniquefieldrequired => 'variable',
459 variable => 'SubscriptionLog',
461 forceupdate => {'explanation' => 1, 'type' => 1},
462 explanation => 'Active this if you want to log Subscription action',
466 uniquefieldrequired => 'variable',
467 variable => 'IssueLog',
469 forceupdate => {'explanation' => 1, 'type' => 1},
470 explanation => 'Active this if you want to log issue.',
474 uniquefieldrequired => 'variable',
475 variable => 'ReturnLog',
477 forceupdate => {'explanation' => 1, 'type' => 1},
478 explanation => 'Active this if you want to log the circulation return',
482 uniquefieldrequired => 'variable',
483 variable => 'Version',
485 forceupdate => {'explanation' => 1, 'type' => 1},
486 explanation => 'Koha Version',
490 uniquefieldrequired => 'variable',
491 variable => 'LetterLog',
493 forceupdate => {'explanation' => 1, 'type' => 1},
494 explanation => 'Active this if you want to log all the letter sent',
498 uniquefieldrequired => 'variable',
499 variable => 'FinesLog',
501 forceupdate => {'explanation' => 1, 'type' => 1},
502 explanation => 'Active this if you want to log fines',
506 uniquefieldrequired => 'variable',
507 variable => 'NoZebra',
509 forceupdate => {'explanation' => 1, 'type' => 1},
510 explanation => 'Active this if you want NOT to use zebra (large libraries should avoid this parameters)',
514 uniquefieldrequired => 'variable',
515 variable => 'NoZebraIndexes',
517 forceupdate => {'explanation' => 1, 'type' => 1},
518 explanation => "Enter a specific hash for NoZebra indexes. Enter : 'indexname' => '100a,245a,500*','index2' => '...'",
522 uniquefieldrequired => 'variable',
523 variable => 'uppercasesurnames',
525 forceupdate => {'explanation' => 1, 'type' => 1},
526 explanation => "Force Surnames to be uppercase",
532 uniquefieldrequired => 'bit',
534 flag => 'editauthorities',
535 flagdesc => 'allow to edit authorities',
539 uniquefieldrequired => 'bit',
542 flagdesc => 'allow to manage serials subscriptions',
546 uniquefieldrequired => 'bit',
549 flagdesc => 'allow to access to the reports module',
553 authorised_values => [
555 uniquefieldrequired => 'id',
556 category => 'SUGGEST',
557 authorised_value => 'Not enough budget',
558 lib => 'This book it too much expensive',
563 my %fielddefinitions = (
565 # { field => 'fieldname',
566 # type => 'fieldtype',
574 field => 'booksellerid',
589 extra => 'auto_increment',
592 field => 'listprice',
593 type => 'varchar(10)',
600 field => 'invoiceprice',
601 type => 'varchar(10)',
611 field => 'notify_id',
619 field => 'notify_level',
630 { field => 'firstname',
634 { field => 'initials',
638 { field => 'B_email',
641 after => 'B_zipcode',
644 field => 'streetnumber', # street number (hidden if streettable table is empty)
650 field => 'streettype', # street table, list builded from a system table
653 after => 'streetnumber',
660 field => 'B_streetnumber', # street number (hidden if streettable table is empty)
666 field => 'B_streettype', # street table, list builded from a system table
669 after => 'B_streetnumber',
678 field => 'address2', # complement address
690 field => 'contactfirstname', # contact's firstname
693 after => 'contactname',
696 field => 'contacttitle', # contact's title
699 after => 'contactfirstname',
702 field => 'branchcode',
703 type => 'varchar(10)',
709 field => 'categorycode',
710 type => 'varchar(10)',
720 type => 'varchar(25)',
728 type => 'varchar(4)',
736 type => 'varchar(30)',
742 field => 'publicationyear',
749 field => 'collectiontitle',
750 type => 'mediumtext',
756 field => 'collectionissn',
757 type => 'mediumtext',
763 field => 'collectionvolume',
764 type => 'mediumtext',
770 field => 'editionstatement',
777 field => 'editionresponsability',
785 deletedbiblioitems => [
788 type => 'varchar(30)',
797 type => 'varchar(15)',
804 field => 'branchprinter',
805 type => 'varchar(100)',
812 field => 'branchcode',
813 type => 'varchar(10)',
821 field => 'frombranch',
822 type => 'VARCHAR(10)',
830 type => 'VARCHAR(10)',
839 field => 'category_type',
847 field => 'categorycode',
848 type => 'varchar(10)',
856 deletedborrowers => [
857 { field => 'firstname',
861 { field => 'initials',
865 { field => 'B_email',
868 after => 'B_zipcode',
871 field => 'streetnumber', # street number (hidden if streettable table is empty)
877 field => 'streettype', # street table, list builded from a system table
880 after => 'streetnumber',
887 field => 'B_streetnumber', # street number (hidden if streettable table is empty)
893 field => 'B_streettype', # street table, list builded from a system table
896 after => 'B_streetnumber',
905 field => 'address2', # complement address
917 field => 'contactfirstname', # contact's firstname
920 after => 'contactname',
923 field => 'contacttitle', # contact's title
926 after => 'contactfirstname',
932 field => 'borrowernumber',
934 null => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
940 field => 'itemnumber',
942 null => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
948 field => 'branchcode',
949 type => 'varchar(10)',
956 field => 'issuedate',
960 default => '0000-00-00',
971 default => '0000-00-00',
975 field => 'cutterextra',
976 type => 'varchar(45)',
983 field => 'issue_date',
991 field => 'homebranch',
992 type => 'varchar(10)',
999 field => 'holdingbranch',
1000 type => 'varchar(10)',
1008 type => 'varchar(10)',
1017 field => 'itemtype',
1018 type => 'varchar(10)',
1041 marc_subfield_structure => [
1043 field => 'defaultvalue',
1052 field => 'expirationdate',
1069 field => 'waitingdate',
1089 field => 'dateadded',
1090 type => 'timestamp',
1094 systempreferences => [
1104 field => 'explanation',
1126 # { indexname => 'index detail'
1130 { indexname => 'PRIMARY',
1136 { indexname => 'booksellerid',
1137 content => 'booksellerid',
1141 { indexname => 'basketno',
1142 content => 'basketno',
1145 aqorderbreakdown => [
1146 { indexname => 'ordernumber',
1147 content => 'ordernumber',
1149 { indexname => 'bookfundid',
1150 content => 'bookfundid',
1154 { indexname => 'isbn',
1157 { indexname => 'publishercode',
1158 content => 'publishercode',
1163 indexname => 'branchcode',
1164 content => 'branchcode',
1168 branchrelations => [
1170 indexname => 'PRIMARY',
1171 content => 'categorycode',
1175 branchrelations => [
1176 { indexname => 'PRIMARY',
1177 content => 'branchcode,categorycode',
1180 { indexname => 'branchcode',
1181 content => 'branchcode',
1183 { indexname => 'categorycode',
1184 content => 'categorycode',
1188 { indexname => 'PRIMARY',
1189 content => 'currency',
1195 indexname => 'categorycode',
1196 content => 'categorycode',
1200 { indexname => 'homebranch',
1201 content => 'homebranch',
1203 { indexname => 'holdingbranch',
1204 content => 'holdingbranch',
1209 indexname => 'itemtype',
1210 content => 'itemtype',
1214 { indexname => 'shelfnumber',
1215 content => 'shelfnumber',
1217 { indexname => 'itemnumber',
1218 content => 'itemnumber',
1222 { indexname => 'PRIMARY',
1229 my %foreign_keys = (
1231 # { key => 'the key in table' (must be indexed)
1232 # foreigntable => 'the foreigntable name', # (the parent)
1233 # foreignkey => 'the foreign key column(s)' # (in the parent)
1234 # onUpdate => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1235 # onDelete => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1238 branchrelations => [
1239 { key => 'branchcode',
1240 foreigntable => 'branches',
1241 foreignkey => 'branchcode',
1242 onUpdate => 'CASCADE',
1243 onDelete => 'CASCADE',
1245 { key => 'categorycode',
1246 foreigntable => 'branchcategories',
1247 foreignkey => 'categorycode',
1248 onUpdate => 'CASCADE',
1249 onDelete => 'CASCADE',
1253 { key => 'shelfnumber',
1254 foreigntable => 'virtualshelf',
1255 foreignkey => 'shelfnumber',
1256 onUpdate => 'CASCADE',
1257 onDelete => 'CASCADE',
1259 { key => 'itemnumber',
1260 foreigntable => 'items',
1261 foreignkey => 'itemnumber',
1262 onUpdate => 'CASCADE',
1263 onDelete => 'CASCADE',
1266 # onDelete is RESTRICT on reference tables (branches, itemtype) as we don't want items to be
1267 # easily deleted, but branches/itemtype not too easy to empty...
1269 { key => 'biblionumber',
1270 foreigntable => 'biblio',
1271 foreignkey => 'biblionumber',
1272 onUpdate => 'CASCADE',
1273 onDelete => 'CASCADE',
1275 { key => 'itemtype',
1276 foreigntable => 'itemtypes',
1277 foreignkey => 'itemtype',
1278 onUpdate => 'CASCADE',
1279 onDelete => 'RESTRICT',
1283 { key => 'biblioitemnumber',
1284 foreigntable => 'biblioitems',
1285 foreignkey => 'biblioitemnumber',
1286 onUpdate => 'CASCADE',
1287 onDelete => 'CASCADE',
1289 { key => 'homebranch',
1290 foreigntable => 'branches',
1291 foreignkey => 'branchcode',
1292 onUpdate => 'CASCADE',
1293 onDelete => 'RESTRICT',
1295 { key => 'holdingbranch',
1296 foreigntable => 'branches',
1297 foreignkey => 'branchcode',
1298 onUpdate => 'CASCADE',
1299 onDelete => 'RESTRICT',
1303 { key => 'booksellerid',
1304 foreigntable => 'aqbooksellers',
1306 onUpdate => 'CASCADE',
1307 onDelete => 'RESTRICT',
1311 { key => 'basketno',
1312 foreigntable => 'aqbasket',
1313 foreignkey => 'basketno',
1314 onUpdate => 'CASCADE',
1315 onDelete => 'CASCADE',
1317 { key => 'biblionumber',
1318 foreigntable => 'biblio',
1319 foreignkey => 'biblionumber',
1320 onUpdate => 'SET NULL',
1321 onDelete => 'SET NULL',
1325 { key => 'listprice',
1326 foreigntable => 'currency',
1327 foreignkey => 'currency',
1328 onUpdate => 'CASCADE',
1329 onDelete => 'CASCADE',
1331 { key => 'invoiceprice',
1332 foreigntable => 'currency',
1333 foreignkey => 'currency',
1334 onUpdate => 'CASCADE',
1335 onDelete => 'CASCADE',
1338 aqorderbreakdown => [
1339 { key => 'ordernumber',
1340 foreigntable => 'aqorders',
1341 foreignkey => 'ordernumber',
1342 onUpdate => 'CASCADE',
1343 onDelete => 'CASCADE',
1345 { key => 'bookfundid',
1346 foreigntable => 'aqbookfund',
1347 foreignkey => 'bookfundid',
1348 onUpdate => 'CASCADE',
1349 onDelete => 'CASCADE',
1352 branchtransfers => [
1353 { key => 'frombranch',
1354 foreigntable => 'branches',
1355 foreignkey => 'branchcode',
1356 onUpdate => 'CASCADE',
1357 onDelete => 'CASCADE',
1359 { key => 'tobranch',
1360 foreigntable => 'branches',
1361 foreignkey => 'branchcode',
1362 onUpdate => 'CASCADE',
1363 onDelete => 'CASCADE',
1365 { key => 'itemnumber',
1366 foreigntable => 'items',
1367 foreignkey => 'itemnumber',
1368 onUpdate => 'CASCADE',
1369 onDelete => 'CASCADE',
1373 { key => 'categorycode',
1374 foreigntable => 'categories',
1375 foreignkey => 'categorycode',
1376 onUpdate => 'CASCADE',
1377 onDelete => 'CASCADE',
1379 { key => 'itemtype',
1380 foreigntable => 'itemtypes',
1381 foreignkey => 'itemtype',
1382 onUpdate => 'CASCADE',
1383 onDelete => 'CASCADE',
1386 issues => [ # constraint is SET NULL : when a borrower or an item is deleted, we keep the issuing record
1388 { key => 'borrowernumber',
1389 foreigntable => 'borrowers',
1390 foreignkey => 'borrowernumber',
1391 onUpdate => 'SET NULL',
1392 onDelete => 'SET NULL',
1394 { key => 'itemnumber',
1395 foreigntable => 'items',
1396 foreignkey => 'itemnumber',
1397 onUpdate => 'SET NULL',
1398 onDelete => 'SET NULL',
1402 { key => 'borrowernumber',
1403 foreigntable => 'borrowers',
1404 foreignkey => 'borrowernumber',
1405 onUpdate => 'CASCADE',
1406 onDelete => 'CASCADE',
1408 { key => 'biblionumber',
1409 foreigntable => 'biblio',
1410 foreignkey => 'biblionumber',
1411 onUpdate => 'CASCADE',
1412 onDelete => 'CASCADE',
1414 { key => 'itemnumber',
1415 foreigntable => 'items',
1416 foreignkey => 'itemnumber',
1417 onUpdate => 'CASCADE',
1418 onDelete => 'CASCADE',
1420 { key => 'branchcode',
1421 foreigntable => 'branches',
1422 foreignkey => 'branchcode',
1423 onUpdate => 'CASCADE',
1424 onDelete => 'CASCADE',
1427 borrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1428 # but prevent deleting a branch as soon as it has 1 borrower !
1429 { key => 'categorycode',
1430 foreigntable => 'categories',
1431 foreignkey => 'categorycode',
1432 onUpdate => 'RESTRICT',
1433 onDelete => 'RESTRICT',
1435 { key => 'branchcode',
1436 foreigntable => 'branches',
1437 foreignkey => 'branchcode',
1438 onUpdate => 'RESTRICT',
1439 onDelete => 'RESTRICT',
1442 deletedborrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1443 # but prevent deleting a branch as soon as it has 1 borrower !
1444 { key => 'categorycode',
1445 foreigntable => 'categories',
1446 foreignkey => 'categorycode',
1447 onUpdate => 'RESTRICT',
1448 onDelete => 'RESTRICT',
1450 { key => 'branchcode',
1451 foreigntable => 'branches',
1452 foreignkey => 'branchcode',
1453 onUpdate => 'RESTRICT',
1454 onDelete => 'RESTRICT',
1458 { key => 'borrowernumber',
1459 foreigntable => 'borrowers',
1460 foreignkey => 'borrowernumber',
1461 onUpdate => 'CASCADE',
1462 onDelete => 'CASCADE',
1464 { key => 'itemnumber',
1465 foreigntable => 'items',
1466 foreignkey => 'itemnumber',
1467 onUpdate => 'SET NULL',
1468 onDelete => 'SET NULL',
1471 auth_tag_structure => [
1472 { key => 'authtypecode',
1473 foreigntable => 'auth_types',
1474 foreignkey => 'authtypecode',
1475 onUpdate => 'CASCADE',
1476 onDelete => 'CASCADE',
1479 # FIXME : don't constraint auth_*_table and auth_word, as they may be replaced by zebra
1484 my %column_change = (
1488 from => 'emailaddress',
1493 from => 'streetaddress',
1495 after => 'initials',
1498 from => 'faxnumber',
1503 from => 'textmessaging',
1509 to => 'contactnote',
1510 after => 'opacnote',
1513 from => 'physstreet',
1518 from => 'streetcity',
1520 after => 'B_address',
1533 from => 'homezipcode',
1540 after => 'B_zipcode',
1545 after => 'dateenrolled',
1548 from => 'guarantor',
1549 to => 'guarantorid',
1550 after => 'contactname',
1553 from => 'altrelationship',
1554 to => 'relationship',
1555 after => 'borrowernotes',
1559 deletedborrowers => [
1561 from => 'emailaddress',
1566 from => 'streetaddress',
1568 after => 'initials',
1571 from => 'faxnumber',
1576 from => 'textmessaging',
1582 to => 'contactnote',
1583 after => 'opacnote',
1586 from => 'physstreet',
1591 from => 'streetcity',
1593 after => 'B_address',
1606 from => 'homezipcode',
1613 after => 'B_zipcode',
1618 after => 'dateenrolled',
1621 from => 'guarantor',
1622 to => 'guarantorid',
1623 after => 'contactname',
1626 from => 'altrelationship',
1627 to => 'relationship',
1628 after => 'borrowernotes',
1634 # MOVE all tables TO UTF-8 and innoDB
1635 $sth = $dbh->prepare("show table status");
1637 while ( my $table = $sth->fetchrow_hashref ) {
1638 next if $table->{Name} eq 'marc_word';
1639 next if $table->{Name} eq 'marc_subfield_table';
1640 next if $table->{Name} eq 'auth_word';
1641 next if $table->{Name} eq 'auth_subfield_table';
1642 if ($table->{Engine} ne 'InnoDB') {
1643 $dbh->do("ALTER TABLE $table->{Name} TYPE = innodb");
1644 print "moving $table->{Name} to InnoDB\n";
1646 unless ($table->{Collation} =~ /^utf8/) {
1647 print "moving $table->{Name} to utf8\n";
1648 $dbh->do("ALTER TABLE $table->{Name} CONVERT TO CHARACTER SET utf8");
1649 $dbh->do("ALTER TABLE $table->{Name} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
1650 # 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 !
1656 foreach my $table (keys %column_change) {
1657 $sth = $dbh->prepare("show columns from $table");
1660 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1662 $types{$column}->{type} ="$type";
1663 $types{$column}->{null} = "$null";
1664 $types{$column}->{key} = "$key";
1665 $types{$column}->{default} = "$default";
1666 $types{$column}->{extra} = "$extra";
1668 my $tablerows = $column_change{$table};
1669 foreach my $row ( @$tablerows ) {
1670 if ($types{$row->{from}}->{type}) {
1671 print "altering $table $row->{from} to $row->{to}\n";
1672 # ALTER TABLE `borrowers` CHANGE `faxnumber` `fax` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
1673 # alter table `borrowers` change `faxnumber` `fax` type text null after phone
1675 "alter table `$table` change `$row->{from}` `$row->{to}` $types{$row->{from}}->{type} ".
1676 ($types{$row->{from}}->{null} eq 'YES'?" NULL":" NOT NULL").
1677 ($types{$row->{from}}->{default}?" default ".$types{$row->{from}}->{default}:"").
1678 "$types{$row->{from}}->{extra} after $row->{after} ";
1685 # Enter here the field you want to delete from DB.
1686 # FIXME :: there is a %uselessfield before which seems doing the same things.
1687 my %fieldtodelete = (
1688 # tablename => [fieldname1,fieldname2,...]
1692 print "removing some unused fields...\n";
1693 foreach my $table ( keys %fieldtodelete ) {
1694 foreach my $field ( @{$fieldtodelete{$table}} ){
1695 print "removing ".$field." from ".$table;
1696 my $sth = $dbh->prepare("ALTER TABLE $table DROP $field");
1699 print "Error : $sth->errstr \n";
1704 # Enter here the line you want to remove from DB.
1705 my %linetodelete = (
1706 # table name => where clause.
1707 userflags => "bit = 8", # delete the 'reserveforself' flags
1711 #-------------------
1716 # Get version of MySQL database engine.
1717 my $mysqlversion = `mysqld --version`;
1718 $mysqlversion =~ /Ver (\S*) /;
1720 if ( $mysqlversion ge '3.23' ) {
1721 print "Could convert to MyISAM database tables...\n" unless $silent;
1724 #---------------------------------
1727 # Collect all tables into a list
1728 $sth = $dbh->prepare("show tables");
1730 while ( my ($table) = $sth->fetchrow ) {
1731 $existingtables{$table} = 1;
1735 # Now add any missing tables
1736 foreach $table ( keys %requiretables ) {
1737 unless ( $existingtables{$table} ) {
1738 print "Adding $table table...\n" unless $silent;
1739 my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1742 print "Error : $sth->errstr \n";
1748 #---------------------------------
1751 foreach $table ( keys %requirefields ) {
1752 print "Check table $table\n" if $debug and not $silent;
1753 $sth = $dbh->prepare("show columns from $table");
1756 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1758 $types{$column} = $type;
1760 foreach $column ( keys %{ $requirefields{$table} } ) {
1761 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
1762 if ( !$types{$column} ) {
1764 # column doesn't exist
1765 print "Adding $column field to $table table...\n" unless $silent;
1766 $query = "alter table $table
1767 add column $column " . $requirefields{$table}->{$column};
1768 print "Execute: $query\n" if $debug;
1769 my $sti = $dbh->prepare($query);
1772 print "**Error : $sti->errstr \n";
1779 foreach $table ( keys %fielddefinitions ) {
1780 print "Check table $table\n" if $debug;
1781 $sth = $dbh->prepare("show columns from $table");
1784 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1786 $definitions->{$column}->{type} = $type;
1787 $definitions->{$column}->{null} = $null;
1788 $definitions->{$column}->{null} = 'NULL' if $null eq 'YES';
1789 $definitions->{$column}->{key} = $key;
1790 $definitions->{$column}->{default} = $default;
1791 $definitions->{$column}->{extra} = $extra;
1793 my $fieldrow = $fielddefinitions{$table};
1794 foreach my $row (@$fieldrow) {
1795 my $field = $row->{field};
1796 my $type = $row->{type};
1797 my $null = $row->{null};
1798 # $null = 'YES' if $row->{null} eq 'NULL';
1799 my $key = $row->{key};
1800 my $default = $row->{default};
1801 # $default="''" unless $default;
1802 my $extra = $row->{extra};
1803 my $def = $definitions->{$field};
1804 my $after = ($row->{after}?" after ".$row->{after}:"");
1806 unless ( $type eq $def->{type}
1807 && $null eq $def->{null}
1808 && $key eq $def->{key}
1809 && $extra eq $def->{extra} )
1811 if ( $null eq '' ) {
1814 if ( $key eq 'PRI' ) {
1815 $key = 'PRIMARY KEY';
1817 unless ( $extra eq 'auto_increment' ) {
1821 # if it's a new column use "add", if it's an old one, use "change".
1823 if ($definitions->{$field}->{type}) {
1824 $action="change $field"
1828 # if it's a primary key, drop the previous pk, before altering the table
1829 print " alter or create $field in $table\n" unless $silent;
1831 if ($key ne 'PRIMARY KEY') {
1832 # warn "alter table $table $action $field $type $null $key $extra default $default $after";
1833 $query = "alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1835 # warn "alter table $table drop primary key, $action $field $type $null $key $extra default $default $after";
1836 # something strange : for indexes UNIQUE, they are reported as primary key here.
1837 # but if you try to run with drop primary key, it fails.
1838 # thus, we run the query twice, one will fail, one will succeed.
1840 $query="alter table $table drop primary key, $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1841 $query="alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1848 print "removing some unused data...\n";
1849 foreach my $table ( keys %linetodelete ) {
1850 foreach my $where ( @{linetodelete{$table}} ){
1851 print "DELETE FROM ".$table." where ".$where;
1853 my $sth = $dbh->prepare("DELETE FROM $table where $where");
1856 print "Error : $sth->errstr \n";
1861 # Populate tables with required data
1863 # synch table and deletedtable.
1864 foreach my $table (('borrowers','items','biblio','biblioitems')) {
1865 my %deletedborrowers;
1866 print "synch'ing $table and deleted$table\n";
1867 $sth = $dbh->prepare("show columns from deleted$table");
1869 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1870 $deletedborrowers{$column}=1;
1872 $sth = $dbh->prepare("show columns from $table");
1875 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1876 unless ($deletedborrowers{$column}) {
1877 my $newcol="alter table deleted$table add $column $type";
1878 if ($null eq 'YES') {
1879 $newcol .= " NULL ";
1881 $newcol .= " NOT NULL ";
1883 $newcol .= "default ".$dbh->quote($default) if $default;
1884 $newcol .= " after $previous" if $previous;
1886 print "creating column $column\n";
1892 # update publisheddate
1894 $sth = $dbh->prepare("select count(*) from serial where publisheddate is NULL");
1896 my ($emptypublished) = $sth->fetchrow;
1897 if ($emptypublished) {
1898 print "Updating publisheddate\n";
1899 $dbh->do("update serial set publisheddate=planneddate where publisheddate is NULL");
1901 foreach my $table ( keys %tabledata ) {
1902 print "Checking for data required in table $table...\n" unless $silent;
1903 my $tablerows = $tabledata{$table};
1904 foreach my $row (@$tablerows) {
1905 my $uniquefieldrequired = $row->{uniquefieldrequired};
1906 my $uniquevalue = $row->{$uniquefieldrequired};
1907 my $forceupdate = $row->{forceupdate};
1910 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1912 $sth->execute($uniquevalue);
1914 foreach my $field (keys %$forceupdate) {
1915 if ($forceupdate->{$field}) {
1916 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1917 $sth->execute($row->{$field}, $uniquevalue);
1921 print "Adding row to $table: " unless $silent;
1925 foreach my $field ( keys %$row ) {
1926 next if $field eq 'uniquefieldrequired';
1927 next if $field eq 'forceupdate';
1928 my $value = $row->{$field};
1929 push @values, $value;
1930 print " $field => $value" unless $silent;
1931 $fieldlist .= "$field,";
1932 $placeholders .= "?,";
1934 print "\n" unless $silent;
1935 $fieldlist =~ s/,$//;
1936 $placeholders =~ s/,$//;
1937 print "insert into $table ($fieldlist) values ($placeholders)";
1940 "insert into $table ($fieldlist) values ($placeholders)");
1941 $sth->execute(@values);
1947 # check indexes and create them when needed
1949 print "Checking for index required...\n" unless $silent;
1950 foreach my $table ( keys %indexes ) {
1952 # read all indexes from $table
1954 $sth = $dbh->prepare("show index from $table");
1956 my %existingindexes;
1957 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow ) {
1958 $existingindexes{$key_name} = 1;
1960 # read indexes to check
1961 my $tablerows = $indexes{$table};
1962 foreach my $row (@$tablerows) {
1963 my $key_name=$row->{indexname};
1964 if ($existingindexes{$key_name} eq 1) {
1965 # print "$key_name existing";
1967 print "\tCreating index $key_name in $table\n";
1969 if ($row->{indexname} eq 'PRIMARY') {
1970 $sql = "alter table $table ADD PRIMARY KEY ($row->{content})";
1972 $sql = "alter table $table ADD INDEX $key_name ($row->{content}) $row->{type}";
1975 print "Error $sql : $dbh->err \n" if $dbh->err;
1981 # check foreign keys and create them when needed
1983 print "Checking for foreign keys required...\n" unless $silent;
1984 foreach my $table ( keys %foreign_keys ) {
1986 # read all indexes from $table
1988 $sth = $dbh->prepare("show table status like '$table'");
1990 my $stat = $sth->fetchrow_hashref;
1991 # read indexes to check
1992 my $tablerows = $foreign_keys{$table};
1993 foreach my $row (@$tablerows) {
1994 my $foreign_table=$row->{foreigntable};
1995 if ($stat->{'Comment'} =~/$foreign_table/) {
1996 # print "$foreign_table existing\n";
1998 print "\tCreating foreign key $foreign_table in $table\n";
1999 # first, drop any orphan value in child table
2000 if ($row->{onDelete} ne "RESTRICT") {
2001 my $sql = "delete from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})";
2003 print "SQL ERROR: $sql : $dbh->err \n" if $dbh->err;
2005 my $sql="alter table $table ADD FOREIGN KEY $row->{key} ($row->{key}) REFERENCES $row->{foreigntable} ($row->{foreignkey})";
2006 $sql .= " on update ".$row->{onUpdate} if $row->{onUpdate};
2007 $sql .= " on delete ".$row->{onDelete} if $row->{onDelete};
2010 print "====================
2011 An error occured during :
2013 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).
2014 You can find those values with select
2015 \t$table.* from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})
2016 ====================\n
2022 # now drop useless tables
2023 foreach $table ( @TableToDelete ) {
2024 if ( $existingtables{$table} ) {
2025 print "Dropping unused table $table\n" if $debug and not $silent;
2026 $dbh->do("drop table $table");
2028 print "Error : $dbh->errstr \n";
2037 # create frameworkcode row in biblio table & fill it with marc_biblio.frameworkcode.
2040 # 1st, get how many biblio we will have to do...
2041 $sth = $dbh->prepare('select count(*) from marc_biblio');
2043 my ($totaltodo) = $sth->fetchrow;
2045 $sth = $dbh->prepare("show columns from biblio");
2048 my $bibliofwexist=0;
2049 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
2050 $bibliofwexist=1 if $column eq 'frameworkcode';
2052 unless ($bibliofwexist) {
2053 print "moving biblioframework to biblio table\n";
2054 $dbh->do('ALTER TABLE `biblio` ADD `frameworkcode` VARCHAR( 4 ) NOT NULL AFTER `biblionumber`');
2055 $sth = $dbh->prepare('select biblionumber,frameworkcode from marc_biblio');
2057 my $sth_update = $dbh->prepare('update biblio set frameworkcode=? where biblionumber=?');
2059 while (my ($biblionumber,$frameworkcode) = $sth->fetchrow) {
2060 $sth_update->execute($frameworkcode,$biblionumber);
2062 print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
2067 # at last, remove useless fields
2068 foreach $table ( keys %uselessfields ) {
2069 my @fields = split /,/,$uselessfields{$table};
2072 foreach my $fieldtodrop (@fields) {
2073 $fieldtodrop =~ s/\t//g;
2074 $fieldtodrop =~ s/\n//g;
2076 $sth = $dbh->prepare("show columns from $table");
2078 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
2080 $exists =1 if ($column eq $fieldtodrop);
2083 print "deleting $fieldtodrop field in $table...\n" unless $silent;
2084 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
2091 # Changing aqbookfund's primary key
2093 $sth=$dbh->prepare("ALTER TABLE `aqbookfund` DROP PRIMARY KEY , ADD PRIMARY KEY ( `bookfundid` , `branchcode` ) ;");
2097 print "upgrade to Koha 3.0 done\n";
2098 SetVersion ($DBversion);
2104 Deal with virtualshelves
2107 $DBversion = "3.00.00.001";
2108 if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
2109 # update virtualshelves table to
2111 $dbh->do("ALTER TABLE `bookshelf` RENAME `virtualshelves`");
2112 $dbh->do("ALTER TABLE `shelfcontents` RENAME `virtualshelfcontents`");
2113 $dbh->do("ALTER TABLE `virtualshelfcontents` ADD `biblionumber` INT( 11 ) NOT NULL");
2114 $dbh->do("UPDATE `virtualshelfcontents` SET biblionumber=(SELECT biblionumber FROM items WHERE items.itemnumber=virtualshelfcontents.itemnumber)");
2115 # drop all foreign keys : otherwise, we can't drop itemnumber field.
2116 DropAllForeignKeys('virtualshelfcontents');
2117 # create the new foreign keys (on biblionumber)
2118 $dbh->do("ALTER TABLE `virtualshelfcontents` ADD FOREIGN KEY biblionumber_fk (biblionumber) REFERENCES biblio (biblionumber) ON UPDATE CASCADE ON DELETE CASCADE");
2119 # re-create the foreign key on virtualshelf
2120 $dbh->do("ALTER TABLE `virtualshelfcontents` ADD FOREIGN KEY shelfnumber_fk (shelfnumber) REFERENCES virtualshelves (shelfnumber) ON UPDATE CASCADE ON DELETE CASCADE");
2121 # now we can drop the itemnumber column
2122 $dbh->do("ALTER TABLE `virtualshelfcontents` DROP `itemnumber`");
2123 print "Upgrade to $DBversion done (virtualshelves)\n";
2124 SetVersion ($DBversion);
2128 Deal with the sessions table that uses CGI::Session
2131 $DBversion = "3.00.00.002";
2132 if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
2133 $dbh->do("DROP TABLE sessions");
2134 $dbh->do("CREATE TABLE `sessions` (
2135 `id` char(32) NOT NULL,
2136 `a_session` text NOT NULL,
2137 UNIQUE KEY `id` (`id`)
2138 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;");
2139 print "Upgrade to $DBversion done (sessions uses CGI::session, new table structure for sessions)\n";
2140 SetVersion ($DBversion);
2144 =item DropAllForeignKeys($table)
2146 Drop all foreign keys of the table $table
2150 sub DropAllForeignKeys {
2152 # get the table description
2153 my $sth = $dbh->prepare("SHOW CREATE TABLE $table");
2155 my $vsc_structure = $sth->fetchrow;
2156 # split on CONSTRAINT keyword
2157 my @fks = split /CONSTRAINT /,$vsc_structure;
2160 # isolate what is before FOREIGN KEY, if there is something, it's a foreign key to drop
2161 $_ = /(.*) FOREIGN KEY.*/;
2164 # we have found 1 foreign, drop it
2165 $dbh->do("ALTER TABLE $table DROP FOREIGN KEY $id");
2177 =item TransformToNum
2179 Transform the Koha version from a 4 parts string
2180 to a number, with just 1 .
2184 sub TransformToNum {
2185 my $version = shift;
2186 # remove the 3 last . to have a Perl number
2187 $version =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
2192 set the DBversion in the systempreferences
2196 my $kohaversion = TransformToNum(shift);
2197 if (C4::Context->preference('Version')) {
2198 my $finish=$dbh->prepare("UPDATE systempreferences SET value=? WHERE variable='Version'");
2199 $finish->execute($kohaversion);
2201 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')");
2202 $finish->execute($kohaversion);
2208 # Revision 1.172 2007/07/19 10:21:22 hdl