5 # This script checks for required updates to the database.
7 # Part of the Koha Library Software www.koha-community.org
8 # Licensed under the GPL.
11 # - Would also be a good idea to offer to do a backup at this time...
13 # NOTE: If you do something more than once in here, make it table driven.
23 use MARC
::File
::XML
( BinaryEncoding
=> 'utf8' );
25 # FIXME - The user might be installing a new database, so can't rely
26 # on /etc/koha.conf anyway.
33 %existingtables, # tables already in database
37 $type, $null, $key, $default, $extra,
44 my $dbh = C4
::Context
->dbh;
45 $|=1; # flushes output
47 my $DBversion = "3.00.00.000";
48 # if we are upgrading from Koha 2.2, then we need to run the complete & long updatedatabase
49 # Tables to add if they don't exist
52 `timestamp` TIMESTAMP NOT NULL ,
53 `user` INT( 11 ) NOT NULL default '0' ,
54 `module` TEXT default '',
55 `action` TEXT default '' ,
56 `object` INT(11) NULL ,
57 `info` TEXT default '' ,
58 PRIMARY KEY ( `timestamp` , `user` )
61 module varchar(20) NOT NULL default '',
62 code varchar(20) NOT NULL default '',
63 name varchar(100) NOT NULL default '',
64 title varchar(200) NOT NULL default '',
66 PRIMARY KEY (module,code)
69 alertid int(11) NOT NULL auto_increment,
70 borrowernumber int(11) NOT NULL default '0',
71 type varchar(10) NOT NULL default '',
72 externalid varchar(20) NOT NULL default '',
73 PRIMARY KEY (alertid),
74 KEY borrowernumber (borrowernumber),
75 KEY type (type,externalid)
78 `idnew` int(10) unsigned NOT NULL auto_increment,
79 `title` varchar(250) NOT NULL default '',
81 `lang` varchar(4) NOT NULL default '',
82 `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
85 repeatable_holidays
=> "(
86 `id` int(11) NOT NULL auto_increment,
87 `branchcode` varchar(10) NOT NULL default '',
88 `weekday` smallint(6) default NULL,
89 `day` smallint(6) default NULL,
90 `month` smallint(6) default NULL,
91 `title` varchar(50) NOT NULL default '',
92 `description` text NOT NULL,
95 special_holidays
=> "(
96 `id` int(11) NOT NULL auto_increment,
97 `branchcode` varchar(10) NOT NULL default '',
98 `day` smallint(6) NOT NULL default '0',
99 `month` smallint(6) NOT NULL default '0',
100 `year` smallint(6) NOT NULL default '0',
101 `isexception` smallint(1) NOT NULL default '1',
102 `title` varchar(50) NOT NULL default '',
103 `description` text NOT NULL,
106 overduerules
=>"(`branchcode` varchar(10) NOT NULL default '',
107 `categorycode` varchar(2) NOT NULL default '',
108 `delay1` int(4) default '0',
109 `letter1` varchar(20) default NULL,
110 `debarred1` varchar(1) default '0',
111 `delay2` int(4) default '0',
112 `debarred2` varchar(1) default '0',
113 `letter2` varchar(20) default NULL,
114 `delay3` int(4) default '0',
115 `letter3` varchar(20) default NULL,
116 `debarred3` int(1) default '0',
117 PRIMARY KEY (`branchcode`,`categorycode`)
119 cities
=> "(`cityid` int auto_increment,
120 `city_name` varchar(100) NOT NULL default '',
121 `city_zipcode` varchar(20),
122 PRIMARY KEY (`cityid`)
124 roadtype
=> "(`roadtypeid` int auto_increment,
125 `road_type` varchar(100) NOT NULL default '',
126 PRIMARY KEY (`roadtypeid`)
130 labelid int(11) NOT NULL auto_increment,
131 batch_id varchar(10) NOT NULL default '1',
132 itemnumber varchar(100) NOT NULL default '',
133 timestamp timestamp(14) NOT NULL,
134 PRIMARY KEY (labelid)
138 id int(4) NOT NULL auto_increment,
139 barcodetype char(100) default '',
140 title int(1) default '0',
141 subtitle int(1) default '0',
142 itemtype int(1) default '0',
143 barcode int(1) default '0',
144 dewey int(1) default '0',
145 class int(1) default '0',
146 subclass int(1) default '0',
147 itemcallnumber int(1) default '0',
148 author int(1) default '0',
149 issn int(1) default '0',
150 isbn int(1) default '0',
151 startlabel int(2) NOT NULL default '1',
152 printingtype char(32) default 'BAR',
153 layoutname char(20) NOT NULL default 'TEST',
154 guidebox int(1) default '0',
155 active tinyint(1) default '1',
156 fonttype char(10) collate utf8_unicode_ci default NULL,
157 ccode char(4) collate utf8_unicode_ci default NULL,
158 callnum_split int(1) default NULL,
159 text_justify char(1) collate utf8_unicode_ci default NULL,
163 reviewid integer NOT NULL auto_increment,
164 borrowernumber integer,
165 biblionumber integer,
168 datereviewed datetime,
169 PRIMARY KEY (reviewid)
171 subscriptionroutinglist
=>"(
172 routingid integer NOT NULL auto_increment,
173 borrowernumber integer,
175 subscriptionid integer,
176 PRIMARY KEY (routingid)
180 notify_id int(11) NOT NULL default '0',
181 `borrowernumber` int(11) NOT NULL default '0',
182 `itemnumber` int(11) NOT NULL default '0',
183 `notify_date` date default NULL,
184 `notify_send_date` date default NULL,
185 `notify_level` int(1) NOT NULL default '0',
186 `method` varchar(20) NOT NULL default ''
190 `charge_id` varchar(5) NOT NULL default '',
191 `description` text NOT NULL,
192 `amount` decimal(28,6) NOT NULL default '0.000000',
193 `min` int(4) NOT NULL default '0',
194 `max` int(4) NOT NULL default '0',
195 `level` int(1) NOT NULL default '0',
196 PRIMARY KEY (`charge_id`)
199 `entry` varchar(255) NOT NULL default '',
200 `weight` bigint(20) NOT NULL default '0',
201 PRIMARY KEY (`entry`)
205 `id` int NOT NULL auto_increment,
206 `biblio_auth_number` int(11) NOT NULL default '0',
207 `operation` char(20) NOT NULL default '',
208 `server` char(20) NOT NULL default '',
210 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci AUTO_INCREMENT=1",
214 my %requirefields = (
215 subscription
=> { 'letter' => 'varchar(20) NULL', 'distributedto' => 'text NULL', 'firstacquidate'=>'date default 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(10) NOT NULL default \'\'', 'manualhistory'=>'TINYINT(1) NOT NULL default 0','internalnotes'=>'LONGTEXT NULL default \'\''},
216 itemtypes
=> { 'imageurl' => 'varchar(200) NULL'},
217 aqbookfund
=> { 'branchcode' => 'varchar(4) NULL'},
218 aqbudget
=> { 'branchcode' => 'varchar(4) NULL'},
219 auth_header
=> { 'marc' => 'BLOB NOT NULL', 'linkid' => 'BIGINT(20) NULL'},
220 auth_subfield_structure
=>{ 'hidden' => 'TINYINT(3) NOT NULL default 0', 'kohafield' => "VARCHAR(45) NULL default ''", 'linkid' => 'TINYINT(1) NOT NULL default 0', 'isurl' => 'TINYINT(1)', 'frameworkcode'=>'VARCHAR(8) NOT NULL'},
221 marc_breeding
=> { 'isbn' => 'varchar(13) NOT NULL'},
222 serial
=>{ 'publisheddate' => 'date AFTER planneddate', 'claimdate' => 'date', 'itemnumber'=>'text NULL','routingnotes'=>'text NULL',},
223 statistics
=> { 'associatedborrower' => 'integer'},
224 z3950servers
=>{ "name" =>"text", "description" => "text NOT NULL",
225 "position" =>"enum('primary','secondary','') NOT NULL default 'primary'", "icon" =>"text",
226 "type" =>"enum('zed','opensearch') NOT NULL default 'zed'",
228 issues
=>{ 'issuedate'=>"date NULL default NULL", },
230 # tablename => { 'field' => 'fieldtype' },
233 # Enter here the table to delete.
234 my @TableToDelete = qw(
241 my %uselessfields = (
242 # tablename => "field1,field2",
243 borrowers
=> "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
244 deletedborrowers
=> "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
245 items
=> "multivolumepart,multivolume,binding",
246 deleteditems
=> "multivolumepart,multivolume,binding",
248 # the other hash contains other actions that can't be done elsewhere. they are done
249 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
251 # The tabledata hash contains data that should be in the tables.
252 # The uniquefieldrequired hash entry is used to determine which (if any) fields
253 # must not exist in the table for this row to be inserted. If the
254 # uniquefieldrequired entry is already in the table, the existing data is not
255 # modified, unless the forceupdate hash entry is also set. Fields in the
256 # anonymous "forceupdate" hash will be forced to be updated to the default
257 # values given in the %tabledata hash.
261 # { uniquefielrequired => 'fieldname', # the primary key in the table
262 # fieldname => fieldvalue,
263 # fieldname2 => fieldvalue2,
266 systempreferences
=> [
268 uniquefieldrequired
=> 'variable',
269 variable
=> 'useDaysMode',
271 forceupdate
=> { 'explanation' => 1,
273 explanation
=> 'Choose the method for calculating due date: select Calendar to use the holidays module, and Days to ignore the holidays module',
275 options
=> 'Calendar|Days|Datedue'
278 uniquefieldrequired
=> 'variable',
279 variable
=> 'DebugLevel',
281 forceupdate
=> { 'explanation' => 1,
283 explanation
=> 'Set the level of error info sent to the browser. 0=none, 1=some, 2=most',
288 uniquefieldrequired
=> 'variable',
289 variable
=> 'BorrowersTitles',
290 value
=> 'Mr|Mrs|Miss|Ms',
291 forceupdate
=> { 'explanation' => 1,
293 explanation
=> 'List all Titles for borrowers',
297 uniquefieldrequired
=> 'variable',
298 variable
=> 'BorrowerMandatoryField',
299 value
=> 'cardnumber|surname|address',
300 forceupdate
=> { 'explanation' => 1,
302 explanation
=> 'List all mandatory fields for borrowers',
306 uniquefieldrequired
=> 'variable',
307 variable
=> 'borrowerRelationship',
308 value
=> 'father|mother,grand-mother',
309 forceupdate
=> { 'explanation' => 1,
311 explanation
=> 'The relationships between a guarantor & a guarantee (separated by | or ,)',
315 uniquefieldrequired
=> 'variable',
316 variable
=> 'ReservesMaxPickUpDelay',
318 forceupdate
=> { 'explanation' => 1,
320 explanation
=> 'Maximum delay to pick up a reserved document',
324 uniquefieldrequired
=> 'variable',
325 variable
=> 'TransfersMaxDaysWarning',
327 forceupdate
=> { 'explanation' => 1,
329 explanation
=> 'Max delay before considering the transfer has potentialy a problem',
333 uniquefieldrequired
=> 'variable',
334 variable
=> 'memberofinstitution',
336 forceupdate
=> { 'explanation' => 1,
338 explanation
=> 'Are your patrons members of institutions',
342 uniquefieldrequired
=> 'variable',
343 variable
=> 'ReadingHistory',
345 forceupdate
=> { 'explanation' => 1,
347 explanation
=> 'Allow reading record info retrievable from issues and oldissues tables',
351 uniquefieldrequired
=> 'variable',
352 variable
=> 'IssuingInProcess',
354 forceupdate
=> { 'explanation' => 1,
356 explanation
=> 'Allow no debt alert if the patron is issuing item that accumulate debt',
360 uniquefieldrequired
=> 'variable',
361 variable
=> 'AutomaticItemReturn',
363 forceupdate
=> { 'explanation' => 1,
365 explanation
=> 'This Variable allow or not to return automaticly to his homebranch',
369 uniquefieldrequired
=> 'variable',
370 variable
=> 'reviewson',
372 forceupdate
=> { 'explanation' => 1,
374 explanation
=> 'Allows patrons to submit reviews from the opac',
378 uniquefieldrequired
=> 'variable',
379 variable
=> 'intranet_includes',
381 forceupdate
=> { 'explanation' => 1,
383 explanation
=> 'The includes directory you want for specific look of Koha (includes or includes_npl for example)',
387 uniquefieldrequired
=> 'variable',
388 variable
=> 'AutoLocation',
390 forceupdate
=> { 'explanation' => 1,
392 explanation
=> 'switch to activate or not Autolocation, if Yes, the Librarian can\'t change his location, it\'s defined by branchip',
396 uniquefieldrequired
=> 'variable',
397 variable
=> 'serialsadditems',
403 explanation
=> 'If set, a new item will be automatically added when receiving an issue',
407 uniquefieldrequired
=> 'variable',
408 variable
=> 'expandedSearchOption',
414 explanation
=> 'search among marc field',
418 uniquefieldrequired
=> 'variable',
419 variable
=> 'RequestOnOpac',
421 forceupdate
=> { 'explanation' => 1,
423 explanation
=> 'option to allow reserves on opac',
427 uniquefieldrequired
=> 'variable',
428 variable
=> 'OpacCloud',
430 forceupdate
=> { 'explanation' => 1,
432 explanation
=> 'Enable / Disable cloud link on OPAC (Require to run misc/cronjobs/build_browser_and_cloud.pl on the server)',
436 uniquefieldrequired
=> 'variable',
437 variable
=> 'OpacBrowser',
439 forceupdate
=> { 'explanation' => 1,
441 explanation
=> 'Enable/Disable browser link on OPAC (Require to run misc/cronjobs/build_browser_and_cloud.pl on the server)',
445 uniquefieldrequired
=> 'variable',
446 variable
=> 'OpacTopissue',
448 forceupdate
=> { 'explanation' => 1,
450 explanation
=> 'If ON, enables the \'most popular items\' link on OPAC. Warning, this is an EXPERIMENTAL feature, turning ON may overload your server',
454 uniquefieldrequired
=> 'variable',
455 variable
=> 'OpacAuthorities',
457 forceupdate
=> { 'explanation' => 1,
459 explanation
=> 'Enable / Disable the search authority link on OPAC',
463 uniquefieldrequired
=> 'variable',
464 variable
=> 'CataloguingLog',
466 forceupdate
=> {'explanation' => 1, 'type' => 1},
467 explanation
=> 'Active this if you want to log cataloguing action.',
471 uniquefieldrequired
=> 'variable',
472 variable
=> 'BorrowersLog',
474 forceupdate
=> {'explanation' => 1, 'type' => 1},
475 explanation
=> 'Active this if you want to log borrowers edition/creation/deletion...',
479 uniquefieldrequired
=> 'variable',
480 variable
=> 'SubscriptionLog',
482 forceupdate
=> {'explanation' => 1, 'type' => 1},
483 explanation
=> 'Active this if you want to log Subscription action',
487 uniquefieldrequired
=> 'variable',
488 variable
=> 'IssueLog',
490 forceupdate
=> {'explanation' => 1, 'type' => 1},
491 explanation
=> 'Active this if you want to log issue.',
495 uniquefieldrequired
=> 'variable',
496 variable
=> 'ReturnLog',
498 forceupdate
=> {'explanation' => 1, 'type' => 1},
499 explanation
=> 'Active this if you want to log the circulation return',
503 uniquefieldrequired
=> 'variable',
504 variable
=> 'Version',
506 forceupdate
=> {'explanation' => 1, 'type' => 1},
507 explanation
=> 'Koha Version',
511 uniquefieldrequired
=> 'variable',
512 variable
=> 'LetterLog',
514 forceupdate
=> {'explanation' => 1, 'type' => 1},
515 explanation
=> 'Active this if you want to log all the letter sent',
519 uniquefieldrequired
=> 'variable',
520 variable
=> 'FinesLog',
522 forceupdate
=> {'explanation' => 1, 'type' => 1},
523 explanation
=> 'Active this if you want to log fines',
527 uniquefieldrequired
=> 'variable',
528 variable
=> 'NoZebra',
530 forceupdate
=> {'explanation' => 1, 'type' => 1},
531 explanation
=> 'Active this if you want NOT to use zebra (large libraries should avoid this parameters)',
535 uniquefieldrequired
=> 'variable',
536 variable
=> 'NoZebraIndexes',
538 forceupdate
=> {'explanation' => 1, 'type' => 1},
539 explanation
=> "Enter a specific hash for NoZebra indexes. Enter : 'indexname' => '100a,245a,500*','index2' => '...'",
543 uniquefieldrequired
=> 'variable',
544 variable
=> 'uppercasesurnames',
546 forceupdate
=> {'explanation' => 1, 'type' => 1},
547 explanation
=> "Force Surnames to be uppercase",
553 uniquefieldrequired
=> 'bit',
555 flag
=> 'editauthorities',
556 flagdesc
=> 'allow to edit authorities',
560 uniquefieldrequired
=> 'bit',
563 flagdesc
=> 'allow to manage serials subscriptions',
567 uniquefieldrequired
=> 'bit',
570 flagdesc
=> 'allow to access to the reports module',
574 authorised_values
=> [
576 uniquefieldrequired
=> 'id',
577 category
=> 'SUGGEST',
578 authorised_value
=> 'Not enough budget',
579 lib
=> 'This book it too much expensive',
584 my %fielddefinitions = (
586 # { field => 'fieldname',
587 # type => 'fieldtype',
595 field
=> 'booksellerid',
603 field
=> 'booksellerinvoicenumber',
604 type
=> 'mediumtext',
613 field
=> 'bookfundid',
614 type
=> 'varchar(10)',
621 field
=> 'branchcode',
622 type
=> 'varchar(10)',
629 field
=> 'bookfundname',
630 type
=> 'mediumtext',
635 after
=> 'bookfundid',
646 extra
=> 'auto_increment',
650 type
=> 'varchar(3)',
657 field
=> 'listprice',
658 type
=> 'varchar(10)',
665 field
=> 'invoiceprice',
666 type
=> 'varchar(10)',
673 field
=> 'invoicedisc',
674 type
=> 'float(6,4)',
682 type
=> 'mediumtext',
690 type
=> 'mediumtext',
698 type
=> 'mediumtext',
706 type
=> 'mediumtext',
713 field
=> 'accountnumber',
714 type
=> 'mediumtext',
721 field
=> 'othersupplier',
722 type
=> 'mediumtext',
729 field
=> 'specialty',
730 type
=> 'mediumtext',
737 field
=> 'booksellerfax',
738 type
=> 'mediumtext',
746 type
=> 'mediumtext',
753 field
=> 'bookselleremail',
754 type
=> 'mediumtext',
761 field
=> 'booksellerurl',
762 type
=> 'mediumtext',
769 field
=> 'contnotes',
770 type
=> 'mediumtext',
778 type
=> 'mediumtext',
788 field
=> 'bookfundid',
789 type
=> 'varchar(10)',
796 field
=> 'branchcode',
797 type
=> 'varchar(10)',
805 aqorderbreakdown
=> [
807 field
=> 'bookfundid',
808 type
=> 'varchar(10)',
815 field
=> 'branchcode',
816 type
=> 'varchar(10)',
826 field
=> 'ordernumber',
834 field
=> 'deliverycomments',
835 type
=> 'mediumtext',
846 type
=> 'mediumtext',
854 type
=> 'varchar(3)',
861 field
=> 'booksellerinvoicenumber',
862 type
=> 'mediumtext',
870 type
=> 'mediumtext',
877 field
=> 'supplierreference',
878 type
=> 'mediumtext',
885 field
=> 'purchaseordernumber',
886 type
=> 'mediumtext',
896 field
=> 'notify_id',
904 field
=> 'notify_level',
912 field
=> 'accountno',
913 type
=> 'smallint(6)',
920 field
=> 'description',
921 type
=> 'mediumtext',
926 type
=> 'mediumtext',
934 field
=> 'authtypecode',
935 type
=> 'varchar(10)',
942 field
=> 'datecreated',
950 field
=> 'origincode',
951 type
=> 'varchar(20)',
958 field
=> 'authtrees',
959 type
=> 'mediumtext',
964 after
=> 'origincode',
968 auth_subfield_structure
=> [
970 field
=> 'authtypecode',
971 type
=> 'varchar(10)',
979 type
=> 'varchar(3)',
986 field
=> 'tagsubfield',
987 type
=> 'varchar(1)',
994 field
=> 'liblibrarian',
995 type
=> 'varchar(255)',
1003 type
=> 'varchar(255)',
1010 field
=> 'authorised_value',
1011 type
=> 'varchar(10)',
1018 field
=> 'value_builder',
1019 type
=> 'varchar(80)',
1027 type
=> 'varchar(255)',
1034 field
=> 'kohafield',
1035 type
=> 'varchar(45)',
1042 field
=> 'frameworkcode',
1043 type
=> 'varchar(8)',
1051 auth_tag_structure
=> [
1053 field
=> 'authtypecode',
1054 type
=> 'varchar(10)',
1061 field
=> 'tagfield',
1062 type
=> 'varchar(3)',
1069 field
=> 'liblibrarian',
1070 type
=> 'varchar(255)',
1078 type
=> 'varchar(255)',
1085 field
=> 'authorised_value',
1086 type
=> 'varchar(10)',
1096 field
=> 'auth_tag_to_report',
1097 type
=> 'varchar(3)',
1105 type
=> 'mediumtext',
1113 authorised_values
=> [
1115 field
=> 'category',
1116 type
=> 'varchar(10)',
1123 field
=> 'authorised_value',
1124 type
=> 'varchar(80)',
1132 type
=> 'varchar(80)',
1140 biblio_framework
=> [
1142 field
=> 'frameworkcode',
1143 type
=> 'varchar(4)',
1150 field
=> 'frameworktext',
1151 type
=> 'varchar(255)',
1161 field
=> 'cardnumber',
1162 type
=> 'varchar(16)',
1168 { field
=> 'surname',
1169 type
=> 'mediumtext',
1172 { field
=> 'firstname',
1177 type
=> 'mediumtext',
1180 { field
=> 'othernames',
1181 type
=> 'mediumtext',
1184 { field
=> 'initials',
1188 { field
=> 'B_email',
1191 after
=> 'B_zipcode',
1194 field
=> 'streetnumber', # street number (hidden if streettable table is empty)
1195 type
=> 'varchar(10)',
1197 after
=> 'initials',
1200 field
=> 'streettype', # street table, list builded from a system table
1201 type
=> 'varchar(50)',
1203 after
=> 'streetnumber',
1210 field
=> 'B_streetnumber', # street number (hidden if streettable table is empty)
1211 type
=> 'varchar(10)',
1216 field
=> 'B_streettype', # street table, list builded from a system table
1217 type
=> 'varchar(50)',
1219 after
=> 'B_streetnumber',
1222 field
=> 'phonepro',
1228 field
=> 'address2', # complement address
1234 field
=> 'emailpro',
1240 field
=> 'contactfirstname', # contact's firstname
1243 after
=> 'contactname',
1246 field
=> 'contacttitle', # contact's title
1249 after
=> 'contactfirstname',
1252 field
=> 'branchcode',
1253 type
=> 'varchar(10)',
1259 field
=> 'categorycode',
1260 type
=> 'varchar(10)',
1267 type
=> 'mediumtext',
1274 type
=> 'mediumtext',
1281 type
=> 'mediumtext',
1288 type
=> 'mediumtext',
1295 type
=> 'mediumtext',
1302 type
=> 'mediumtext',
1308 field
=> 'contactname',
1309 type
=> 'mediumtext',
1315 field
=> 'opacnote',
1316 type
=> 'mediumtext',
1322 field
=> 'borrowernotes',
1323 type
=> 'mediumtext',
1330 type
=> 'varchar(1)',
1339 field
=> 'itemtype',
1340 type
=> 'varchar(10)',
1348 type
=> 'varchar(25)',
1356 type
=> 'varchar(4)',
1364 type
=> 'varchar(30)',
1370 field
=> 'publicationyear',
1377 field
=> 'collectiontitle',
1378 type
=> 'mediumtext',
1382 after
=> 'volumeddesc',
1385 field
=> 'collectionissn',
1390 after
=> 'collectiontitle',
1393 field
=> 'collectionvolume',
1394 type
=> 'mediumtext',
1398 after
=> 'collectionissn',
1401 field
=> 'editionstatement',
1406 after
=> 'collectionvolume',
1409 field
=> 'editionresponsibility',
1414 after
=> 'editionstatement',
1418 type
=> 'mediumtext',
1425 type
=> 'mediumtext',
1432 type
=> 'mediumtext',
1442 type
=> 'mediumtext',
1449 type
=> 'mediumtext',
1455 field
=> 'unititle',
1456 type
=> 'mediumtext',
1462 field
=> 'seriestitle',
1463 type
=> 'mediumtext',
1469 field
=> 'abstract',
1470 type
=> 'mediumtext',
1477 type
=> 'mediumtext',
1483 field
=> 'frameworkcode',
1484 type
=> 'varchar(4)',
1488 after
=> 'biblionumber',
1495 type
=> 'mediumtext',
1502 type
=> 'mediumtext',
1508 field
=> 'unititle',
1509 type
=> 'mediumtext',
1515 field
=> 'seriestitle',
1516 type
=> 'mediumtext',
1522 field
=> 'abstract',
1523 type
=> 'mediumtext',
1530 type
=> 'mediumtext',
1536 field
=> 'frameworkcode',
1537 type
=> 'varchar(4)',
1541 after
=> 'biblionumber',
1544 deletedbiblioitems
=> [
1546 field
=> 'itemtype',
1547 type
=> 'varchar(10)',
1554 type
=> 'varchar(30)',
1560 field
=> 'itemtype',
1561 type
=> 'varchar(10)',
1568 type
=> 'mediumtext',
1575 type
=> 'mediumtext',
1582 type
=> 'mediumtext',
1591 field
=> 'shelfname',
1592 type
=> 'varchar(255)',
1599 type
=> 'varchar(80)',
1605 field
=> 'category',
1606 type
=> 'varchar(1)',
1613 branchcategories
=> [
1615 field
=> 'codedescription',
1616 type
=> 'mediumtext',
1625 field
=> 'branchip',
1626 type
=> 'varchar(15)',
1633 field
=> 'branchprinter',
1634 type
=> 'varchar(100)',
1641 field
=> 'branchcode',
1642 type
=> 'varchar(10)',
1648 field
=> 'branchname',
1649 type
=> 'mediumtext',
1655 field
=> 'branchaddress1',
1656 type
=> 'mediumtext',
1662 field
=> 'branchaddress2',
1663 type
=> 'mediumtext',
1669 field
=> 'branchaddress3',
1670 type
=> 'mediumtext',
1676 field
=> 'branchphone',
1677 type
=> 'mediumtext',
1683 field
=> 'branchfax',
1684 type
=> 'mediumtext',
1690 field
=> 'branchemail',
1691 type
=> 'mediumtext',
1698 branchrelations
=> [
1700 field
=> 'branchcode',
1701 type
=> 'VARCHAR(10)',
1708 field
=> 'categorycode',
1709 type
=> 'VARCHAR(10)',
1719 field
=> 'frombranch',
1720 type
=> 'VARCHAR(10)',
1727 field
=> 'tobranch',
1728 type
=> 'VARCHAR(10)',
1734 field
=> 'comments',
1735 type
=> 'mediumtext',
1744 field
=> 'category_type',
1745 type
=> 'varchar(1)',
1752 field
=> 'categorycode',
1753 type
=> 'varchar(10)',
1760 field
=> 'description',
1761 type
=> 'mediumtext',
1769 deletedborrowers
=> [
1771 field
=> 'branchcode',
1772 type
=> 'varchar(10)',
1778 field
=> 'categorycode',
1779 type
=> 'varchar(2)',
1786 type
=> 'mediumtext',
1792 field
=> 'borrowernotes',
1793 type
=> 'mediumtext',
1799 field
=> 'contactname',
1800 type
=> 'mediumtext',
1807 type
=> 'mediumtext',
1813 field
=> 'B_zipcode',
1814 type
=> 'varchar(25)',
1821 type
=> 'varchar(25)',
1829 type
=> 'mediumtext',
1836 type
=> 'mediumtext',
1843 type
=> 'mediumtext',
1850 type
=> 'mediumtext',
1855 { field
=> 'surname',
1856 type
=> 'mediumtext',
1859 { field
=> 'firstname',
1863 { field
=> 'initials',
1868 type
=> 'mediumtext',
1871 { field
=> 'othernames',
1872 type
=> 'mediumtext',
1875 { field
=> 'B_email',
1878 after
=> 'B_zipcode',
1881 field
=> 'streetnumber', # street number (hidden if streettable table is empty)
1882 type
=> 'varchar(10)',
1885 after
=> 'initials',
1888 field
=> 'streettype', # street table, list builded from a system table
1889 type
=> 'varchar(50)',
1892 after
=> 'streetnumber',
1899 field
=> 'B_streetnumber', # street number (hidden if streettable table is empty)
1900 type
=> 'varchar(10)',
1905 field
=> 'B_streettype', # street table, list builded from a system table
1906 type
=> 'varchar(50)',
1908 after
=> 'B_streetnumber',
1911 field
=> 'phonepro',
1917 field
=> 'address2', # complement address
1923 field
=> 'emailpro',
1929 field
=> 'contactfirstname', # contact's firstname
1932 after
=> 'contactname',
1935 field
=> 'contacttitle', # contact's title
1938 after
=> 'contactfirstname',
1942 type
=> 'varchar(1)',
1951 field
=> 'borrowernumber',
1953 null
=> 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
1959 field
=> 'itemnumber',
1961 null
=> 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
1967 field
=> 'branchcode',
1968 type
=> 'varchar(10)',
1975 field
=> 'issuedate',
1984 type
=> 'varchar(4)',
1991 field
=> 'issuingbranch',
1992 type
=> 'varchar(18)',
2001 field
=> 'categorycode',
2002 type
=> 'varchar(10)',
2008 field
=> 'branchcode',
2009 type
=> 'varchar(10)',
2015 field
=> 'itemtype',
2016 type
=> 'varchar(10)',
2033 field
=> 'cutterextra',
2034 type
=> 'varchar(45)',
2041 field
=> 'homebranch',
2042 type
=> 'varchar(10)',
2049 field
=> 'holdingbranch',
2050 type
=> 'varchar(10)',
2058 type
=> 'varchar(10)',
2066 type
=> 'mediumtext',
2073 field
=> 'itemnotes',
2074 type
=> 'mediumtext',
2085 type
=> 'mediumtext',
2092 field
=> 'itemnotes',
2093 type
=> 'mediumtext',
2103 field
=> 'itemtype',
2104 type
=> 'varchar(10)',
2111 field
=> 'description',
2112 type
=> 'MEDIUMTEXT',
2134 marc_subfield_structure
=> [
2136 field
=> 'defaultvalue',
2143 field
=> 'authtypecode',
2144 type
=> 'varchar(20)',
2151 field
=> 'tagfield',
2152 type
=> 'varchar(3)',
2159 field
=> 'tagsubfield',
2160 type
=> 'varchar(1)',
2167 field
=> 'authorised_value',
2168 type
=> 'varchar(20)',
2176 type
=> 'varchar(1100)',
2184 marc_tag_structure
=> [
2186 field
=> 'tagfield',
2187 type
=> 'varchar(3)',
2194 field
=> 'liblibrarian',
2195 type
=> 'varchar(255)',
2203 type
=> 'varchar(255)',
2210 field
=> 'authorised_value',
2211 type
=> 'varchar(10)',
2218 field
=> 'frameworkcode',
2219 type
=> 'varchar(4)',
2229 field
=> 'expirationdate',
2247 field
=> 'printername',
2248 type
=> 'varchar(40)',
2255 field
=> 'printqueue',
2256 type
=> 'varchar(20)',
2263 field
=> 'printtype',
2264 type
=> 'varchar(20)',
2272 reserveconstraints
=> [
2274 field
=> 'reservedate',
2285 field
=> 'waitingdate',
2293 field
=> 'reservedate',
2301 field
=> 'constrainttype',
2302 type
=> 'varchar(1)',
2307 after
=> 'biblionumber',
2310 field
=> 'branchcode',
2311 type
=> 'varchar(10)',
2318 field
=> 'reservenotes',
2319 type
=> 'mediumtext',
2327 type
=> 'varchar(1)',
2337 field
=> 'planneddate',
2351 after
=> 'planneddate',
2357 field
=> 'dateadded',
2358 type
=> 'timestamp',
2366 type
=> 'varchar(10)',
2370 field
=> 'datetime',
2376 field
=> 'itemtype',
2377 type
=> 'varchar(10)',
2382 type
=> 'mediumtext',
2389 field
=> 'startdate',
2398 type
=> 'mediumtext',
2405 field
=> 'monthlength',
2414 subscriptionhistory
=> [
2416 field
=> 'histstartdate',
2433 systempreferences
=> [
2436 type
=> 'mediumtext',
2451 field
=> 'explanation',
2470 type
=> 'mediumtext',
2480 type
=> 'varchar(30)',
2487 field
=> 'flagdesc',
2488 type
=> 'varchar(255)',
2498 type
=> 'mediumtext',
2509 # { indexname => 'index detail'
2513 { indexname
=> 'accountoffsets_ibfk_1',
2514 content
=> 'borrowernumber',
2518 { indexname
=> 'PRIMARY',
2524 { indexname
=> 'booksellerid',
2525 content
=> 'booksellerid',
2529 { indexname
=> 'basketno',
2530 content
=> 'basketno',
2533 aqorderbreakdown
=> [
2534 { indexname
=> 'ordernumber',
2535 content
=> 'ordernumber',
2537 { indexname
=> 'bookfundid',
2538 content
=> 'bookfundid',
2542 { indexname
=> 'isbn',
2545 { indexname
=> 'publishercode',
2546 content
=> 'publishercode',
2551 indexname
=> 'borrowernumber',
2552 content
=> 'borrowernumber',
2559 indexname
=> 'branchcode',
2560 content
=> 'branchcode',
2564 branchrelations
=> [
2566 indexname
=> 'PRIMARY',
2567 content
=> 'categorycode',
2571 branchrelations
=> [
2572 { indexname
=> 'PRIMARY',
2573 content
=> 'branchcode,categorycode',
2576 { indexname
=> 'branchcode',
2577 content
=> 'branchcode',
2579 { indexname
=> 'categorycode',
2580 content
=> 'categorycode',
2584 { indexname
=> 'PRIMARY',
2585 content
=> 'currency',
2591 indexname
=> 'categorycode',
2592 content
=> 'categorycode',
2597 indexname
=> 'categorycode',
2598 content
=> 'categorycode',
2601 indexname
=> 'itemtype',
2602 content
=> 'itemtype',
2606 { indexname
=> 'homebranch',
2607 content
=> 'homebranch',
2609 { indexname
=> 'holdingbranch',
2610 content
=> 'holdingbranch',
2615 indexname
=> 'itemtype',
2616 content
=> 'itemtype',
2620 { indexname
=> 'shelfnumber',
2621 content
=> 'shelfnumber',
2623 { indexname
=> 'itemnumber',
2624 content
=> 'itemnumber',
2628 { indexname
=> 'PRIMARY',
2635 my %foreign_keys = (
2637 # { key => 'the key in table' (must be indexed)
2638 # foreigntable => 'the foreigntable name', # (the parent)
2639 # foreignkey => 'the foreign key column(s)' # (in the parent)
2640 # onUpdate => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
2641 # onDelete => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
2644 branchrelations
=> [
2645 { key
=> 'branchcode',
2646 foreigntable
=> 'branches',
2647 foreignkey
=> 'branchcode',
2648 onUpdate
=> 'CASCADE',
2649 onDelete
=> 'CASCADE',
2651 { key
=> 'categorycode',
2652 foreigntable
=> 'branchcategories',
2653 foreignkey
=> 'categorycode',
2654 onUpdate
=> 'CASCADE',
2655 onDelete
=> 'CASCADE',
2659 { key
=> 'shelfnumber',
2660 foreigntable
=> 'bookshelf',
2661 foreignkey
=> 'shelfnumber',
2662 onUpdate
=> 'CASCADE',
2663 onDelete
=> 'CASCADE',
2665 { key
=> 'itemnumber',
2666 foreigntable
=> 'items',
2667 foreignkey
=> 'itemnumber',
2668 onUpdate
=> 'CASCADE',
2669 onDelete
=> 'CASCADE',
2672 # onDelete is RESTRICT on reference tables (branches, itemtype) as we don't want items to be
2673 # easily deleted, but branches/itemtype not too easy to empty...
2675 { key
=> 'biblionumber',
2676 foreigntable
=> 'biblio',
2677 foreignkey
=> 'biblionumber',
2678 onUpdate
=> 'CASCADE',
2679 onDelete
=> 'CASCADE',
2683 { key
=> 'biblioitemnumber',
2684 foreigntable
=> 'biblioitems',
2685 foreignkey
=> 'biblioitemnumber',
2686 onUpdate
=> 'CASCADE',
2687 onDelete
=> 'CASCADE',
2689 { key
=> 'homebranch',
2690 foreigntable
=> 'branches',
2691 foreignkey
=> 'branchcode',
2692 onUpdate
=> 'CASCADE',
2693 onDelete
=> 'RESTRICT',
2695 { key
=> 'holdingbranch',
2696 foreigntable
=> 'branches',
2697 foreignkey
=> 'branchcode',
2698 onUpdate
=> 'CASCADE',
2699 onDelete
=> 'RESTRICT',
2703 { key
=> 'booksellerid',
2704 foreigntable
=> 'aqbooksellers',
2706 onUpdate
=> 'CASCADE',
2707 onDelete
=> 'RESTRICT',
2711 { key
=> 'basketno',
2712 foreigntable
=> 'aqbasket',
2713 foreignkey
=> 'basketno',
2714 onUpdate
=> 'CASCADE',
2715 onDelete
=> 'CASCADE',
2717 { key
=> 'biblionumber',
2718 foreigntable
=> 'biblio',
2719 foreignkey
=> 'biblionumber',
2720 onUpdate
=> 'SET NULL',
2721 onDelete
=> 'SET NULL',
2725 { key
=> 'listprice',
2726 foreigntable
=> 'currency',
2727 foreignkey
=> 'currency',
2728 onUpdate
=> 'CASCADE',
2729 onDelete
=> 'CASCADE',
2731 { key
=> 'invoiceprice',
2732 foreigntable
=> 'currency',
2733 foreignkey
=> 'currency',
2734 onUpdate
=> 'CASCADE',
2735 onDelete
=> 'CASCADE',
2738 aqorderbreakdown
=> [
2739 { key
=> 'ordernumber',
2740 foreigntable
=> 'aqorders',
2741 foreignkey
=> 'ordernumber',
2742 onUpdate
=> 'CASCADE',
2743 onDelete
=> 'CASCADE',
2745 { key
=> 'bookfundid',
2746 foreigntable
=> 'aqbookfund',
2747 foreignkey
=> 'bookfundid',
2748 onUpdate
=> 'CASCADE',
2749 onDelete
=> 'CASCADE',
2752 branchtransfers
=> [
2753 { key
=> 'frombranch',
2754 foreigntable
=> 'branches',
2755 foreignkey
=> 'branchcode',
2756 onUpdate
=> 'CASCADE',
2757 onDelete
=> 'CASCADE',
2759 { key
=> 'tobranch',
2760 foreigntable
=> 'branches',
2761 foreignkey
=> 'branchcode',
2762 onUpdate
=> 'CASCADE',
2763 onDelete
=> 'CASCADE',
2765 { key
=> 'itemnumber',
2766 foreigntable
=> 'items',
2767 foreignkey
=> 'itemnumber',
2768 onUpdate
=> 'CASCADE',
2769 onDelete
=> 'CASCADE',
2772 issues
=> [ # constraint is SET NULL : when a borrower or an item is deleted, we keep the issuing record
2774 { key
=> 'borrowernumber',
2775 foreigntable
=> 'borrowers',
2776 foreignkey
=> 'borrowernumber',
2777 onUpdate
=> 'SET NULL',
2778 onDelete
=> 'SET NULL',
2780 { key
=> 'itemnumber',
2781 foreigntable
=> 'items',
2782 foreignkey
=> 'itemnumber',
2783 onUpdate
=> 'SET NULL',
2784 onDelete
=> 'SET NULL',
2788 { key
=> 'borrowernumber',
2789 foreigntable
=> 'borrowers',
2790 foreignkey
=> 'borrowernumber',
2791 onUpdate
=> 'CASCADE',
2792 onDelete
=> 'CASCADE',
2794 { key
=> 'biblionumber',
2795 foreigntable
=> 'biblio',
2796 foreignkey
=> 'biblionumber',
2797 onUpdate
=> 'CASCADE',
2798 onDelete
=> 'CASCADE',
2800 { key
=> 'itemnumber',
2801 foreigntable
=> 'items',
2802 foreignkey
=> 'itemnumber',
2803 onUpdate
=> 'CASCADE',
2804 onDelete
=> 'CASCADE',
2806 { key
=> 'branchcode',
2807 foreigntable
=> 'branches',
2808 foreignkey
=> 'branchcode',
2809 onUpdate
=> 'CASCADE',
2810 onDelete
=> 'CASCADE',
2813 borrowers
=> [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
2814 # but prevent deleting a branch as soon as it has 1 borrower !
2815 { key
=> 'categorycode',
2816 foreigntable
=> 'categories',
2817 foreignkey
=> 'categorycode',
2818 onUpdate
=> 'RESTRICT',
2819 onDelete
=> 'RESTRICT',
2821 { key
=> 'branchcode',
2822 foreigntable
=> 'branches',
2823 foreignkey
=> 'branchcode',
2824 onUpdate
=> 'RESTRICT',
2825 onDelete
=> 'RESTRICT',
2829 { key
=> 'borrowernumber',
2830 foreigntable
=> 'borrowers',
2831 foreignkey
=> 'borrowernumber',
2832 onUpdate
=> 'CASCADE',
2833 onDelete
=> 'CASCADE',
2835 { key
=> 'itemnumber',
2836 foreigntable
=> 'items',
2837 foreignkey
=> 'itemnumber',
2838 onUpdate
=> 'SET NULL',
2839 onDelete
=> 'SET NULL',
2843 { key
=> 'borrowernumber',
2844 foreigntable
=> 'borrowers',
2845 foreignkey
=> 'borrowernumber',
2846 onUpdate
=> 'CASCADE',
2847 onDelete
=> 'CASCADE',
2850 auth_tag_structure
=> [
2851 { key
=> 'authtypecode',
2852 foreigntable
=> 'auth_types',
2853 foreignkey
=> 'authtypecode',
2854 onUpdate
=> 'CASCADE',
2855 onDelete
=> 'CASCADE',
2858 # FIXME : don't constraint auth_*_table and auth_word, as they may be replaced by zebra
2863 my %column_change = (
2867 from
=> 'emailaddress',
2872 from
=> 'streetaddress',
2874 after
=> 'initials',
2877 from
=> 'faxnumber',
2882 from
=> 'textmessaging',
2888 to
=> 'contactnote',
2889 after
=> 'opacnote',
2892 from
=> 'physstreet',
2897 from
=> 'streetcity',
2899 after
=> 'B_address',
2912 from
=> 'homezipcode',
2919 after
=> 'B_zipcode',
2924 after
=> 'dateenrolled',
2927 from
=> 'guarantor',
2928 to
=> 'guarantorid',
2929 after
=> 'contactname',
2932 from
=> 'altrelationship',
2933 to
=> 'relationship',
2934 after
=> 'borrowernotes',
2938 deletedborrowers
=> [
2940 from
=> 'emailaddress',
2945 from
=> 'streetaddress',
2947 after
=> 'initials',
2950 from
=> 'faxnumber',
2955 from
=> 'textmessaging',
2961 to
=> 'contactnote',
2962 after
=> 'opacnote',
2965 from
=> 'physstreet',
2970 from
=> 'streetcity',
2972 after
=> 'B_address',
2985 from
=> 'homezipcode',
2992 after
=> 'B_zipcode',
2997 after
=> 'dateenrolled',
3000 from
=> 'guarantor',
3001 to
=> 'guarantorid',
3002 after
=> 'contactname',
3005 from
=> 'altrelationship',
3006 to
=> 'relationship',
3007 after
=> 'borrowernotes',
3013 # MOVE all tables TO UTF-8 and innoDB
3014 $sth = $dbh->prepare("show table status");
3016 while ( my $table = $sth->fetchrow_hashref ) {
3017 next if $table->{Name
} eq 'marc_word';
3018 next if $table->{Name
} eq 'marc_subfield_table';
3019 next if $table->{Name
} eq 'auth_word';
3020 next if $table->{Name
} eq 'auth_subfield_table';
3021 if ($table->{Engine
} ne 'InnoDB') {
3022 print "moving $table->{Name} to InnoDB\n";
3023 $dbh->do("ALTER TABLE $table->{Name} ENGINE = innodb");
3025 unless ($table->{Collation
} =~ /^utf8/) {
3026 print "moving $table->{Name} to utf8\n";
3027 $dbh->do("ALTER TABLE $table->{Name} CONVERT TO CHARACTER SET utf8");
3028 $dbh->do("ALTER TABLE $table->{Name} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
3029 # 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 !
3034 # list of columns that must exist for %column_change to be
3035 # processed without error, but which do not necessarily exist
3036 # in all 2.2 databases
3037 my %required_prereq_fields = (
3038 deletedborrowers
=> [
3039 [ 'textmessaging', 'mediumtext AFTER faxnumber' ],
3040 [ 'password', 'varchar(30) default NULL' ],
3041 [ 'flags', 'int(11) default NULL' ],
3042 [ 'userid', 'varchar(30) default NULL' ],
3043 [ 'homezipcode', 'varchar(25) default NULL' ],
3044 [ 'zipcode', 'varchar(25) default NULL' ],
3045 [ 'sort1', 'varchar(80) default NULL' ],
3046 [ 'sort2', 'varchar(80) default NULL' ],
3050 foreach my $table ( keys %required_prereq_fields ) {
3051 print "Check table $table\n" if $debug and not $silent;
3052 $sth = $dbh->prepare("show columns from $table");
3055 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
3057 $types{$column} = $type;
3059 foreach my $entry ( @
{ $required_prereq_fields{$table} } ) {
3060 ($column, $type) = @
{ $entry };
3061 print " Check column $column [$type]\n" if $debug and not $silent;
3062 if ( !$types{$column} ) {
3064 # column doesn't exist
3065 print "Adding $column field to $table table...\n" unless $silent;
3066 $query = "alter table $table
3067 add column $column " . $type;
3068 print "Execute: $query\n" if $debug;
3069 my $sti = $dbh->prepare($query);
3072 print "**Error : $sti->errstr \n";
3079 foreach my $table (keys %column_change) {
3080 $sth = $dbh->prepare("show columns from $table");
3083 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
3085 $types{$column}->{type
} ="$type";
3086 $types{$column}->{null
} = "$null";
3087 $types{$column}->{key
} = "$key";
3088 $types{$column}->{default} = "$default";
3089 $types{$column}->{extra
} = "$extra";
3091 my $tablerows = $column_change{$table};
3092 foreach my $row ( @
$tablerows ) {
3093 if ($types{$row->{from
}}->{type
}) {
3094 print "altering $table $row->{from} to $row->{to}\n";
3095 # ALTER TABLE `borrowers` CHANGE `faxnumber` `fax` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
3096 # alter table `borrowers` change `faxnumber` `fax` type text null after phone
3098 "alter table `$table` change `$row->{from}` `$row->{to}` $types{$row->{from}}->{type} ".
3099 ($types{$row->{from
}}->{null
} eq 'YES'?
" NULL":" NOT NULL").
3100 ($types{$row->{from
}}->{default}?
" default ".$types{$row->{from
}}->{default}:"").
3101 "$types{$row->{from}}->{extra} after $row->{after} ";
3108 # Enter here the field you want to delete from DB.
3109 # FIXME :: there is a %uselessfield before which seems doing the same things.
3110 my %fieldtodelete = (
3111 # tablename => [fieldname1,fieldname2,...]
3115 print "removing some unused fields...\n";
3116 foreach my $table ( keys %fieldtodelete ) {
3117 foreach my $field ( @
{$fieldtodelete{$table}} ){
3118 print "removing ".$field." from ".$table;
3119 my $sth = $dbh->prepare("ALTER TABLE $table DROP $field");
3122 print "Error : $sth->errstr \n";
3127 # Enter here the line you want to remove from DB.
3128 my %linetodelete = (
3129 # table name => where clause.
3130 userflags
=> [ "bit = 8" ], # delete the 'reserveforself' flags
3134 #-------------------
3139 # Get version of MySQL database engine.
3140 my $mysqlversion = `mysqld --version`;
3141 $mysqlversion =~ /Ver (\S*) /;
3143 if ( $mysqlversion ge '3.23' ) {
3144 print "Could convert to MyISAM database tables...\n" unless $silent;
3147 #---------------------------------
3150 # Collect all tables into a list
3151 $sth = $dbh->prepare("show tables");
3153 while ( my ($table) = $sth->fetchrow ) {
3154 $existingtables{$table} = 1;
3158 # Now add any missing tables
3159 foreach my $table ( keys %requiretables ) {
3160 unless ( $existingtables{$table} ) {
3161 print "Adding $table table...\n" unless $silent;
3162 my $sth = $dbh->prepare("create table $table $requiretables{$table} ENGINE=InnoDB DEFAULT CHARSET=utf8");
3165 print "Error : $sth->errstr \n";
3171 #---------------------------------
3174 foreach my $table ( keys %requirefields ) {
3175 print "Check table $table\n" if $debug and not $silent;
3176 $sth = $dbh->prepare("show columns from $table");
3179 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
3181 $types{$column} = $type;
3183 foreach my $column ( keys %{ $requirefields{$table} } ) {
3184 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
3185 if ( !$types{$column} ) {
3187 # column doesn't exist
3188 print "Adding $column field to $table table...\n" unless $silent;
3189 $query = "alter table $table
3190 add column $column " . $requirefields{$table}->{$column};
3191 print "Execute: $query\n" if $debug;
3192 my $sti = $dbh->prepare($query);
3195 print "**Error : $sti->errstr \n";
3202 foreach my $table ( sort keys %fielddefinitions ) {
3203 print "Check table $table\n" if $debug;
3204 $sth = $dbh->prepare("show columns from $table");
3207 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
3209 $definitions->{$column}->{type
} = $type;
3210 $definitions->{$column}->{null
} = $null;
3211 $definitions->{$column}->{null
} = 'NULL' if $null eq 'YES';
3212 $definitions->{$column}->{key
} = $key;
3213 $definitions->{$column}->{default} = $default;
3214 $definitions->{$column}->{extra
} = $extra;
3216 my $fieldrow = $fielddefinitions{$table};
3217 foreach my $row (@
$fieldrow) {
3218 my $field = $row->{field
};
3219 my $type = $row->{type
};
3220 my $null = $row->{null
};
3221 # $null = 'YES' if $row->{null} eq 'NULL';
3222 my $key = $row->{key
};
3223 my $default = $row->{default};
3224 # $default="''" unless $default;
3225 my $extra = $row->{extra
};
3226 my $def = $definitions->{$field};
3227 my $after = ($row->{after
}?
" after ".$row->{after
}:"");
3229 unless ( $type eq $def->{type
}
3230 && $null eq $def->{null
}
3231 && $key eq $def->{key
}
3232 && $default eq $def->{default}
3233 && $extra eq $def->{extra
} )
3235 if ( $null eq '' ) {
3238 if ( $key eq 'PRI' ) {
3239 $key = 'PRIMARY KEY';
3241 unless ( $extra eq 'auto_increment' ) {
3245 # if it's a new column use "add", if it's an old one, use "change".
3247 if ($definitions->{$field}->{type
}) {
3248 $action="change `$field`"
3252 # if it's a primary key, drop the previous pk, before altering the table
3253 print " alter or create $field in $table\n" unless $silent;
3255 if ($key ne 'PRIMARY KEY') {
3256 # warn "alter table $table $action $field $type $null $key $extra default $default $after";
3257 $query = "alter table $table $action `$field` $type $null $key $extra ".
3258 GetDefaultClause
($default)." $after";
3260 # warn "alter table $table drop primary key, $action $field $type $null $key $extra default $default $after";
3261 # something strange : for indexes UNIQUE, they are reported as primary key here.
3262 # but if you try to run with drop primary key, it fails.
3263 # thus, we run the query twice, one will fail, one will succeed.
3265 $query="alter table $table drop primary key, $action `$field` $type $null $key $extra ".
3266 GetDefaultClause
($default)." $after";
3267 $query="alter table $table $action `$field` $type $null $key $extra ".
3268 GetDefaultClause
($default)." $after";
3270 $dbh->do($query) or warn "Error while executing: $query";
3275 print "removing some unused data...\n";
3276 foreach my $table ( keys %linetodelete ) {
3277 foreach my $where ( @
{$linetodelete{$table}} ){
3278 print "DELETE FROM ".$table." where ".$where;
3280 my $sth = $dbh->prepare("DELETE FROM $table where $where");
3283 print "Error : $sth->errstr \n";
3288 # Populate tables with required data
3290 # synch table and deletedtable.
3291 foreach my $table (('borrowers','items','biblio','biblioitems')) {
3292 my %deletedborrowers;
3293 print "synch'ing $table and deleted$table\n";
3294 $sth = $dbh->prepare("show columns from deleted$table");
3296 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
3297 $deletedborrowers{$column}=1;
3299 $sth = $dbh->prepare("show columns from $table");
3302 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
3303 unless ($deletedborrowers{$column}) {
3304 my $newcol="alter table deleted$table add $column $type";
3305 if ($null eq 'YES') {
3306 $newcol .= " NULL ";
3308 $newcol .= " NOT NULL ";
3310 $newcol .= "default ".$dbh->quote($default) if $default;
3311 $newcol .= " after $previous" if $previous;
3313 print "creating column $column\n";
3319 # update publisheddate
3321 $sth = $dbh->prepare("select count(*) from serial where publisheddate is NULL");
3323 my ($emptypublished) = $sth->fetchrow;
3324 if ($emptypublished) {
3325 print "Updating publisheddate\n";
3326 $dbh->do("update serial set publisheddate=planneddate where publisheddate is NULL");
3328 # Why are we setting publisheddate = planneddate ?? if we don't have the data, we don't know it.
3329 # now, let's get rid of 000-00-00's.
3331 $dbh->do("update serial set publisheddate=NULL where publisheddate = 0");
3332 $dbh->do("update subscription set firstacquidate=startdate where firstacquidate = 0");
3334 foreach my $table ( keys %tabledata ) {
3335 print "Checking for data required in table $table...\n" unless $silent;
3336 my $tablerows = $tabledata{$table};
3337 foreach my $row (@
$tablerows) {
3338 my $uniquefieldrequired = $row->{uniquefieldrequired
};
3339 my $uniquevalue = $row->{$uniquefieldrequired};
3340 my $forceupdate = $row->{forceupdate
};
3343 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
3345 $sth->execute($uniquevalue);
3347 foreach my $field (keys %$forceupdate) {
3348 if ($forceupdate->{$field}) {
3349 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
3350 $sth->execute($row->{$field}, $uniquevalue);
3354 print "Adding row to $table: " unless $silent;
3358 foreach my $field ( keys %$row ) {
3359 next if $field eq 'uniquefieldrequired';
3360 next if $field eq 'forceupdate';
3361 my $value = $row->{$field};
3362 push @values, $value;
3363 print " $field => $value" unless $silent;
3364 $fieldlist .= "$field,";
3365 $placeholders .= "?,";
3367 print "\n" unless $silent;
3368 $fieldlist =~ s/,$//;
3369 $placeholders =~ s/,$//;
3370 print "insert into $table ($fieldlist) values ($placeholders)";
3373 "insert into $table ($fieldlist) values ($placeholders)");
3374 $sth->execute(@values);
3380 # check indexes and create them when needed
3382 print "Checking for index required...\n" unless $silent;
3383 foreach my $table ( keys %indexes ) {
3385 # read all indexes from $table
3387 $sth = $dbh->prepare("show index from $table");
3389 my %existingindexes;
3390 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow ) {
3391 $existingindexes{$key_name} = 1;
3393 # read indexes to check
3394 my $tablerows = $indexes{$table};
3395 foreach my $row (@
$tablerows) {
3396 my $key_name=$row->{indexname
};
3397 if ($existingindexes{$key_name} eq 1 and not $row->{force
}) {
3398 # print "$key_name existing";
3400 print "\tCreating index $key_name in $table\n";
3402 if ($row->{indexname
} eq 'PRIMARY' or $row->{type
} eq 'PRI') {
3403 $sql = "alter table $table ADD PRIMARY KEY ($row->{content})";
3405 $sql = "alter table $table ADD INDEX $key_name ($row->{content}) $row->{type}";
3408 print "Error $sql : $dbh->err \n" if $dbh->err;
3414 # check foreign keys and create them when needed
3416 print "Checking for foreign keys required...\n" unless $silent;
3417 foreach my $table ( sort keys %foreign_keys ) {
3419 # read all indexes from $table
3421 $sth = $dbh->prepare("show table status like '$table'");
3423 my $stat = $sth->fetchrow_hashref;
3424 # read indexes to check
3425 my $tablerows = $foreign_keys{$table};
3426 foreach my $row (@
$tablerows) {
3427 my $foreign_table=$row->{foreigntable
};
3428 if ($stat->{'Comment'} =~/$foreign_table/) {
3429 # print "$foreign_table existing\n";
3431 print "\tCreating foreign key $foreign_table in $table\n";
3432 # first, drop any orphan value in child table
3433 if ($row->{onDelete
} ne "RESTRICT") {
3434 my $sql = "delete from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})";
3436 print "SQL ERROR: $sql : $dbh->err \n" if $dbh->err;
3438 my $sql="alter table $table ADD FOREIGN KEY $row->{key} ($row->{key}) REFERENCES $row->{foreigntable} ($row->{foreignkey})";
3439 $sql .= " on update ".$row->{onUpdate
} if $row->{onUpdate
};
3440 $sql .= " on delete ".$row->{onDelete
} if $row->{onDelete
};
3443 print "====================
3444 An error occurred during :
3446 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).
3447 You can find those values with select
3448 \t$table.* from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})
3449 ====================\n
3455 # now drop useless tables
3456 foreach my $table ( @TableToDelete ) {
3457 if ( $existingtables{$table} ) {
3458 print "Dropping unused table $table\n" if $debug and not $silent;
3459 $dbh->do("drop table $table");
3461 print "Error : $dbh->errstr \n";
3470 # create frameworkcode row in biblio table & fill it with marc_biblio.frameworkcode.
3473 # 1st, get how many biblio we will have to do...
3474 $sth = $dbh->prepare('select count(*) from marc_biblio');
3476 my ($totaltodo) = $sth->fetchrow;
3478 $sth = $dbh->prepare("show columns from biblio");
3481 my $bibliofwexist=0;
3482 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
3483 $bibliofwexist=1 if $column eq 'frameworkcode';
3485 unless ($bibliofwexist) {
3486 print "moving biblioframework to biblio table\n";
3487 $dbh->do('ALTER TABLE `biblio` ADD `frameworkcode` VARCHAR( 4 ) NOT NULL AFTER `biblionumber`');
3488 $sth = $dbh->prepare('select biblionumber,frameworkcode from marc_biblio');
3490 my $sth_update = $dbh->prepare('update biblio set frameworkcode=? where biblionumber=?');
3492 while (my ($biblionumber,$frameworkcode) = $sth->fetchrow) {
3493 $sth_update->execute($frameworkcode,$biblionumber);
3495 print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
3500 # at last, remove useless fields
3501 foreach my $table ( keys %uselessfields ) {
3502 my @fields = split (/,/,$uselessfields{$table});
3504 foreach my $fieldtodrop (@fields) {
3505 $fieldtodrop =~ s/\t//g;
3506 $fieldtodrop =~ s/\n//g;
3508 $sth = $dbh->prepare("show columns from $table");
3510 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
3512 $exists =1 if ($column eq $fieldtodrop);
3515 print "deleting $fieldtodrop field in $table...\n" unless $silent;
3516 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
3523 # Changing aqbookfund's primary key
3525 $sth=$dbh->prepare("ALTER TABLE `aqbookfund` DROP PRIMARY KEY , ADD PRIMARY KEY ( `bookfundid` , `branchcode` ) ;");
3529 # drop extra key on borrowers.borrowernumber
3530 $dbh->do("ALTER TABLE borrowers DROP KEY borrowernumber");
3532 # update enrolmentperiod
3533 $dbh->do("UPDATE categories SET enrolmentperiod = enrolmentperiod * 12");
3535 print "upgrade to Koha 3.0 done\n";
3536 SetVersion
($DBversion);
3538 =head1 GetDefaultClause
3540 Generate a default clause (for an ALTER TABLE command)
3544 sub GetDefaultClause
{
3545 my $default = shift;
3547 return "" unless defined $default;
3548 return "" if $default eq '';
3549 return "default ''" if $default eq "''";
3550 return "default NULL" if $default eq "NULL";
3551 return "default " . $dbh->quote($default);
3554 =head1 TransformToNum
3556 Transform the Koha version from a 4 parts string
3557 to a number, with just 1.
3561 sub TransformToNum
{
3562 my $version = shift;
3563 # remove the 3 last . to have a Perl number
3564 $version =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
3570 set the DBversion in the systempreferences
3575 my $kohaversion = TransformToNum
(shift);
3576 if (C4
::Context
->preference('Version')) {
3577 my $finish=$dbh->prepare("UPDATE systempreferences SET value=? WHERE variable='Version'");
3578 $finish->execute($kohaversion);
3580 my $finish=$dbh->prepare("INSERT into systempreferences (variable,value,explanation) values ('Version',?,'The Koha database version. WARNING: Do not change this value manually, it is maintained by the webinstaller')");
3581 $finish->execute($kohaversion);
3586 # Revision 1.172 2007/07/19 10:21:22 hdl