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 print "connected to your DB. Checking & modifying it\n" unless $silent;
48 $|=1; # flushes output
53 # Tables to add if they don't exist
55 categorytable => "(categorycode char(5) NOT NULL default '',
56 description text default '',
57 itemtypecodes text default '',
58 PRIMARY KEY (categorycode)
60 subcategorytable => "(subcategorycode char(5) NOT NULL default '',
61 description text default '',
62 itemtypecodes text default '',
63 PRIMARY KEY (subcategorycode)
65 mediatypetable => "(mediatypecode char(5) NOT NULL default '',
66 description text default '',
67 itemtypecodes text default '',
68 PRIMARY KEY (mediatypecode)
71 `timestamp` TIMESTAMP NOT NULL ,
72 `user` INT( 11 ) NOT NULL ,
73 `module` TEXT default '',
74 `action` TEXT default '' ,
75 `object` INT(11) NULL ,
76 `info` TEXT default '' ,
77 PRIMARY KEY ( `timestamp` , `user` )
80 module varchar(20) NOT NULL default '',
81 code varchar(20) NOT NULL default '',
82 name varchar(100) NOT NULL default '',
83 title varchar(200) NOT NULL default '',
85 PRIMARY KEY (module,code)
88 alertid int(11) NOT NULL auto_increment,
89 borrowernumber int(11) NOT NULL default '0',
90 type varchar(10) NOT NULL default '',
91 externalid varchar(20) NOT NULL default '',
92 PRIMARY KEY (alertid),
93 KEY borrowernumber (borrowernumber),
94 KEY type (type,externalid)
97 `idnew` int(10) unsigned NOT NULL auto_increment,
98 `title` varchar(250) NOT NULL default '',
100 `lang` varchar(4) NOT NULL default '',
101 `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
102 PRIMARY KEY (`idnew`)
104 repeatable_holidays => "(
105 `id` int(11) NOT NULL auto_increment,
106 `branchcode` varchar(4) NOT NULL default '',
107 `weekday` smallint(6) default NULL,
108 `day` smallint(6) default NULL,
109 `month` smallint(6) default NULL,
110 `title` varchar(50) NOT NULL default '',
111 `description` text NOT NULL,
114 special_holidays => "(
115 `id` int(11) NOT NULL auto_increment,
116 `branchcode` varchar(4) NOT NULL default '',
117 `day` smallint(6) NOT NULL default '0',
118 `month` smallint(6) NOT NULL default '0',
119 `year` smallint(6) NOT NULL default '0',
120 `isexception` smallint(1) NOT NULL default '1',
121 `title` varchar(50) NOT NULL default '',
122 `description` text NOT NULL,
125 overduerules =>"(`branchcode` varchar(255) NOT NULL default '',
126 `categorycode` char(2) NOT NULL default '',
127 `delay1` int(4) default '0',
128 `letter1` varchar(20) default NULL,
129 `debarred1` char(1) default '0',
130 `delay2` int(4) default '0',
131 `debarred2` char(1) default '0',
132 `letter2` varchar(20) default NULL,
133 `delay3` int(4) default '0',
134 `letter3` varchar(20) default NULL,
135 `debarred3` int(1) default '0',
136 PRIMARY KEY (`branchcode`,`categorycode`)
138 cities => "(`cityid` int auto_increment,
139 `city_name` char(100) NOT NULL,
140 `city_zipcode` char(20),
141 PRIMARY KEY (`cityid`)
143 roadtype => "(`roadtypeid` int auto_increment,
144 `road_type` char(100) NOT NULL,
145 PRIMARY KEY (`roadtypeid`)
149 labelid int(11) NOT NULL auto_increment,
150 itemnumber varchar(100) NOT NULL default '',
151 timestamp timestamp(14) NOT NULL,
152 PRIMARY KEY (labelid)
156 id int(4) NOT NULL auto_increment,
157 barcodetype char(100) default '',
158 title tinyint(1) default '0',
159 isbn tinyint(1) default '0',
160 itemtype tinyint(1) default '0',
161 barcode tinyint(1) default '0',
162 dewey tinyint(1) default '0',
163 class tinyint(1) default '0',
164 author tinyint(1) default '0',
165 papertype char(100) default '',
166 startrow int(2) default NULL,
170 reviewid integer NOT NULL auto_increment,
171 borrowernumber integer,
172 biblionumber integer,
175 datereviewed datetime,
176 PRIMARY KEY (reviewid)
178 borrowers_to_borrowers => "(
182 subscriptionroutinglist=>"(
183 routingid integer NOT NULL auto_increment,
184 borrowernumber integer,
186 subscriptionid integer,
187 PRIMARY KEY (routingid)
191 notify_id int(11) NOT NULL default '0',
192 `borrowernumber` int(11) NOT NULL default '0',
193 `itemnumber` int(11) NOT NULL default '0',
194 `notify_date` date NOT NULL default '0000-00-00',
195 `notify_send_date` date default NULL,
196 `notify_level` int(1) NOT NULL default '0',
197 `method` varchar(20) NOT NULL default ''
201 `charge_id` varchar(5) NOT NULL default '',
202 `description` text NOT NULL,
203 `amount` decimal(28,6) NOT NULL default '0.000000',
204 `min` int(4) NOT NULL default '0',
205 `max` int(4) NOT NULL default '0',
206 `level` int(1) NOT NULL default '0',
207 PRIMARY KEY (`charge_id`)
210 `entry` varchar(255) NOT NULL default '',
211 `weight` bigint(20) NOT NULL default '0',
212 PRIMARY KEY (`entry`)
216 `id` int NOT NULL auto_increment,
217 `biblio_auth_number` int NOT NULL,
218 `operation` char(20) NOT NULL,
219 `server` char(20) NOT NULL ,
221 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci AUTO_INCREMENT=1",
225 my %requirefields = (
226 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 \'\''},
227 itemtypes => { 'imageurl' => 'char(200) NULL'},
228 aqbookfund => { 'branchcode' => 'varchar(4) NULL'},
229 aqbudget => { 'branchcode' => 'varchar(4) NULL'},
230 auth_header => { 'marc' => 'BLOB NOT NULL', 'linkid' => 'BIGINT(20) NULL'},
231 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'},
232 marc_breeding => { 'isbn' => 'varchar(13) NOT NULL'},
233 serial =>{ 'publisheddate' => 'date', 'claimdate' => 'date', 'itemnumber'=>'text NULL','routingnotes'=>'text NULL',},
234 statistics => { 'associatedborrower' => 'integer'},
235 z3950servers =>{ "name" =>"text", "description" => "text NOT NULL",
236 "position" =>"enum('primary','secondary','') NOT NULL default 'primary'", "icon" =>"text",
237 "type" =>"enum('zed','opensearch') NOT NULL default 'zed'",
239 issues =>{ 'issuedate'=>"date NOT NULL default '0000-00-00'", },
241 # tablename => { 'field' => 'fieldtype' },
244 # Enter here the table to delete.
245 my @TableToDelete = qw(
252 my %uselessfields = (
253 # tablename => "field1,field2",
254 borrowers => "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
255 deletedborrowers=> "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
257 # the other hash contains other actions that can't be done elsewhere. they are done
258 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
260 # The tabledata hash contains data that should be in the tables.
261 # The uniquefieldrequired hash entry is used to determine which (if any) fields
262 # must not exist in the table for this row to be inserted. If the
263 # uniquefieldrequired entry is already in the table, the existing data is not
264 # modified, unless the forceupdate hash entry is also set. Fields in the
265 # anonymous "forceupdate" hash will be forced to be updated to the default
266 # values given in the %tabledata hash.
270 # { uniquefielrequired => 'fieldname', # the primary key in the table
271 # fieldname => fieldvalue,
272 # fieldname2 => fieldvalue2,
275 systempreferences => [
277 uniquefieldrequired => 'variable',
278 variable => 'useDaysMode',
280 forceupdate => { 'explanation' => 1,
282 explanation => 'How to calculate return dates : Calendar means holidays will be controled, Days means the return date don\'t depend on holidays',
284 options => 'Calendar|Days'
287 uniquefieldrequired => 'variable',
288 variable => 'BorrowersTitles',
289 value => 'Mr|Mrs|Miss|Ms',
290 forceupdate => { 'explanation' => 1,
292 explanation => 'List all Titles for borrowers',
296 uniquefieldrequired => 'variable',
297 variable => 'BorrowerMandatoryField',
298 value => 'cardnumber|surname|address',
299 forceupdate => { 'explanation' => 1,
301 explanation => 'List all mandatory fields for borrowers',
305 uniquefieldrequired => 'variable',
306 variable => 'borrowerRelationship',
307 value => 'father|mother,grand-mother',
308 forceupdate => { 'explanation' => 1,
310 explanation => 'The relationships between a guarantor & a guarantee (separated by | or ,)',
314 uniquefieldrequired => 'variable',
315 variable => 'ReservesMaxPickUpDelay',
317 forceupdate => { 'explanation' => 1,
319 explanation => 'Maximum delay to pick up a reserved document',
323 uniquefieldrequired => 'variable',
324 variable => 'TransfersMaxDaysWarning',
326 forceupdate => { 'explanation' => 1,
328 explanation => 'Max delay before considering the transfer has potentialy a problem',
332 uniquefieldrequired => 'variable',
333 variable => 'memberofinstitution',
335 forceupdate => { 'explanation' => 1,
337 explanation => 'Are your patrons members of institutions',
341 uniquefieldrequired => 'variable',
342 variable => 'ReadingHistory',
344 forceupdate => { 'explanation' => 1,
346 explanation => 'Allow reading record info retrievable from issues and oldissues tables',
350 uniquefieldrequired => 'variable',
351 variable => 'IssuingInProcess',
353 forceupdate => { 'explanation' => 1,
355 explanation => 'Allow no debt alert if the patron is issuing item that accumulate debt',
359 uniquefieldrequired => 'variable',
360 variable => 'AutomaticItemReturn',
362 forceupdate => { 'explanation' => 1,
364 explanation => 'This Variable allow or not to return automaticly to his homebranch',
368 uniquefieldrequired => 'variable',
369 variable => 'reviewson',
371 forceupdate => { 'explanation' => 1,
373 explanation => 'Allows patrons to submit reviews from the opac',
377 uniquefieldrequired => 'variable',
378 variable => 'intranet_includes',
380 forceupdate => { 'explanation' => 1,
382 explanation => 'The includes directory you want for specific look of Koha (includes or includes_npl for example)',
386 uniquefieldrequired => 'variable',
387 variable => 'AutoLocation',
389 forceupdate => { 'explanation' => 1,
391 explanation => 'switch to activate or not Autolocation, if Yes, the Librarian can\'t change his location, it\'s defined by branchip',
395 uniquefieldrequired => 'variable',
396 variable => 'serialsadditems',
402 explanation => 'If set, a new item will be automatically added when receiving an issue',
406 uniquefieldrequired => 'variable',
407 variable => 'expandedSearchOption',
413 explanation => 'search among marc field',
417 uniquefieldrequired => 'variable',
418 variable => 'RequestOnOpac',
420 forceupdate => { 'explanation' => 1,
422 explanation => 'option to allow reserves on opac',
426 uniquefieldrequired => 'variable',
427 variable => 'OpacCloud',
429 forceupdate => { 'explanation' => 1,
431 explanation => 'Enable / Disable cloud link on OPAC',
435 uniquefieldrequired => 'variable',
436 variable => 'OpacBrowser',
438 forceupdate => { 'explanation' => 1,
440 explanation => 'Enable/Disable browser link on OPAC (needs to set misc/cronjob/build_browser.pl)',
444 uniquefieldrequired => 'variable',
445 variable => 'OpacTopissue',
447 forceupdate => { 'explanation' => 1,
449 explanation => 'Enable / Disable the top issue link on OPAC',
453 uniquefieldrequired => 'variable',
454 variable => 'OpacAuthorities',
456 forceupdate => { 'explanation' => 1,
458 explanation => 'Enable / Disable the search authority link on OPAC',
462 uniquefieldrequired => 'variable',
463 variable => 'CataloguingLog',
465 forceupdate => {'explanation' => 1, 'type' => 1},
466 explanation => 'Active this if you want to log cataloguing action.',
470 uniquefieldrequired => 'variable',
471 variable => 'BorrowersLog',
473 forceupdate => {'explanation' => 1, 'type' => 1},
474 explanation => 'Active this if you want to log borrowers edition/creation/deletion...',
478 uniquefieldrequired => 'variable',
479 variable => 'SubscriptionLog',
481 forceupdate => {'explanation' => 1, 'type' => 1},
482 explanation => 'Active this if you want to log Subscription action',
486 uniquefieldrequired => 'variable',
487 variable => 'IssueLog',
489 forceupdate => {'explanation' => 1, 'type' => 1},
490 explanation => 'Active this if you want to log issue.',
494 uniquefieldrequired => 'variable',
495 variable => 'ReturnLog',
497 forceupdate => {'explanation' => 1, 'type' => 1},
498 explanation => 'Active this if you want to log the circulation return',
502 uniquefieldrequired => 'variable',
503 variable => 'Version',
505 forceupdate => {'explanation' => 1, 'type' => 1},
506 explanation => 'Koha Version',
510 uniquefieldrequired => 'variable',
511 variable => 'LetterLog',
513 forceupdate => {'explanation' => 1, 'type' => 1},
514 explanation => 'Active this if you want to log all the letter sent',
518 uniquefieldrequired => 'variable',
519 variable => 'FinesLog',
521 forceupdate => {'explanation' => 1, 'type' => 1},
522 explanation => 'Active this if you want to log fines',
526 uniquefieldrequired => 'variable',
527 variable => 'NoZebra',
529 forceupdate => {'explanation' => 1, 'type' => 1},
530 explanation => 'Active this if you want NOT to use zebra (large libraries should avoid this parameters)',
534 uniquefieldrequired => 'variable',
535 variable => 'NoZebraIndexes',
537 forceupdate => {'explanation' => 1, 'type' => 1},
538 explanation => "Enter a specific hash for NoZebra indexes. Enter : 'indexname' => '100a,245a,500*','index2' => '...'",
544 uniquefieldrequired => 'bit',
546 flag => 'editauthorities',
547 flagdesc => 'allow to edit authorities',
551 uniquefieldrequired => 'bit',
554 flagdesc => 'allow to manage serials subscriptions',
558 uniquefieldrequired => 'bit',
561 flagdesc => 'allow to access to the reports module',
565 authorised_values => [
567 uniquefieldrequired => 'id',
568 category => 'SUGGEST',
569 authorised_value => 'Not enough budget',
570 lib => 'This book it too much expensive',
575 my %fielddefinitions = (
577 # { field => 'fieldname',
578 # type => 'fieldtype',
586 field => 'booksellerid',
601 extra => 'auto_increment',
604 field => 'listprice',
605 type => 'varchar(10)',
612 field => 'invoiceprice',
613 type => 'varchar(10)',
623 field => 'notify_id',
631 field => 'notify_level',
642 { field => 'firstname',
646 { field => 'initials',
650 { field => 'B_email',
653 after => 'B_zipcode',
656 field => 'streetnumber', # street number (hidden if streettable table is empty)
662 field => 'streettype', # street table, list builded from a system table
665 after => 'streetnumber',
672 field => 'B_streetnumber', # street number (hidden if streettable table is empty)
678 field => 'B_streettype', # street table, list builded from a system table
681 after => 'B_streetnumber',
690 field => 'address2', # complement address
702 field => 'contactfirstname', # contact's firstname
705 after => 'contactname',
708 field => 'contacttitle', # contact's title
711 after => 'contactfirstname',
714 field => 'branchcode',
715 type => 'varchar(10)',
721 field => 'categorycode',
722 type => 'varchar(10)',
732 type => 'varchar(25)',
740 type => 'varchar(4)',
750 type => 'varchar(15)',
757 field => 'branchprinter',
758 type => 'varchar(100)',
765 field => 'branchcode',
766 type => 'varchar(10)',
774 field => 'frombranch',
775 type => 'VARCHAR(10)',
783 type => 'VARCHAR(10)',
792 field => 'category_type',
800 field => 'categorycode',
801 type => 'varchar(10)',
809 deletedborrowers => [
810 { field => 'firstname',
814 { field => 'initials',
818 { field => 'B_email',
821 after => 'B_zipcode',
824 field => 'streetnumber', # street number (hidden if streettable table is empty)
830 field => 'streettype', # street table, list builded from a system table
833 after => 'streetnumber',
840 field => 'B_streetnumber', # street number (hidden if streettable table is empty)
846 field => 'B_streettype', # street table, list builded from a system table
849 after => 'B_streetnumber',
858 field => 'address2', # complement address
870 field => 'contactfirstname', # contact's firstname
873 after => 'contactname',
876 field => 'contacttitle', # contact's title
879 after => 'contactfirstname',
885 field => 'borrowernumber',
887 null => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
893 field => 'itemnumber',
895 null => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
901 field => 'branchcode',
902 type => 'varchar(10)',
909 field => 'issuedate',
913 default => '0000-00-00',
924 default => '0000-00-00',
928 field => 'cutterextra',
929 type => 'varchar(45)',
936 field => 'issue_date',
944 field => 'homebranch',
945 type => 'varchar(10)',
952 field => 'holdingbranch',
953 type => 'varchar(10)',
961 type => 'varchar(10)',
971 type => 'varchar(10)',
985 marc_subfield_structure => [
987 field => 'defaultvalue',
996 field => 'expirationdate',
1013 field => 'waitingdate',
1033 field => 'dateadded',
1034 type => 'timestamp',
1038 systempreferences => [
1048 field => 'explanation',
1070 # { indexname => 'index detail'
1074 { indexname => 'PRIMARY',
1080 { indexname => 'booksellerid',
1081 content => 'booksellerid',
1085 { indexname => 'basketno',
1086 content => 'basketno',
1089 aqorderbreakdown => [
1090 { indexname => 'ordernumber',
1091 content => 'ordernumber',
1093 { indexname => 'bookfundid',
1094 content => 'bookfundid',
1098 { indexname => 'isbn',
1101 { indexname => 'publishercode',
1102 content => 'publishercode',
1107 indexname => 'branchcode',
1108 content => 'branchcode',
1112 branchrelations => [
1114 indexname => 'PRIMARY',
1115 content => 'categorycode',
1119 branchrelations => [
1120 { indexname => 'PRIMARY',
1121 content => 'branchcode,categorycode',
1124 { indexname => 'branchcode',
1125 content => 'branchcode',
1127 { indexname => 'categorycode',
1128 content => 'categorycode',
1132 { indexname => 'PRIMARY',
1133 content => 'currency',
1139 indexname => 'categorycode',
1140 content => 'categorycode',
1144 { indexname => 'homebranch',
1145 content => 'homebranch',
1147 { indexname => 'holdingbranch',
1148 content => 'holdingbranch',
1153 indexname => 'itemtype',
1154 content => 'itemtype',
1158 { indexname => 'shelfnumber',
1159 content => 'shelfnumber',
1161 { indexname => 'itemnumber',
1162 content => 'itemnumber',
1166 { indexname => 'PRIMARY',
1173 my %foreign_keys = (
1175 # { key => 'the key in table' (must be indexed)
1176 # foreigntable => 'the foreigntable name', # (the parent)
1177 # foreignkey => 'the foreign key column(s)' # (in the parent)
1178 # onUpdate => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1179 # onDelete => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1182 branchrelations => [
1183 { key => 'branchcode',
1184 foreigntable => 'branches',
1185 foreignkey => 'branchcode',
1186 onUpdate => 'CASCADE',
1187 onDelete => 'CASCADE',
1189 { key => 'categorycode',
1190 foreigntable => 'branchcategories',
1191 foreignkey => 'categorycode',
1192 onUpdate => 'CASCADE',
1193 onDelete => 'CASCADE',
1197 { key => 'shelfnumber',
1198 foreigntable => 'bookshelf',
1199 foreignkey => 'shelfnumber',
1200 onUpdate => 'CASCADE',
1201 onDelete => 'CASCADE',
1203 { key => 'itemnumber',
1204 foreigntable => 'items',
1205 foreignkey => 'itemnumber',
1206 onUpdate => 'CASCADE',
1207 onDelete => 'CASCADE',
1210 # onDelete is RESTRICT on reference tables (branches, itemtype) as we don't want items to be
1211 # easily deleted, but branches/itemtype not too easy to empty...
1213 { key => 'biblionumber',
1214 foreigntable => 'biblio',
1215 foreignkey => 'biblionumber',
1216 onUpdate => 'CASCADE',
1217 onDelete => 'CASCADE',
1219 { key => 'itemtype',
1220 foreigntable => 'itemtypes',
1221 foreignkey => 'itemtype',
1222 onUpdate => 'CASCADE',
1223 onDelete => 'RESTRICT',
1227 { key => 'biblioitemnumber',
1228 foreigntable => 'biblioitems',
1229 foreignkey => 'biblioitemnumber',
1230 onUpdate => 'CASCADE',
1231 onDelete => 'CASCADE',
1233 { key => 'homebranch',
1234 foreigntable => 'branches',
1235 foreignkey => 'branchcode',
1236 onUpdate => 'CASCADE',
1237 onDelete => 'RESTRICT',
1239 { key => 'holdingbranch',
1240 foreigntable => 'branches',
1241 foreignkey => 'branchcode',
1242 onUpdate => 'CASCADE',
1243 onDelete => 'RESTRICT',
1247 { key => 'booksellerid',
1248 foreigntable => 'aqbooksellers',
1250 onUpdate => 'CASCADE',
1251 onDelete => 'RESTRICT',
1255 { key => 'basketno',
1256 foreigntable => 'aqbasket',
1257 foreignkey => 'basketno',
1258 onUpdate => 'CASCADE',
1259 onDelete => 'CASCADE',
1261 { key => 'biblionumber',
1262 foreigntable => 'biblio',
1263 foreignkey => 'biblionumber',
1264 onUpdate => 'SET NULL',
1265 onDelete => 'SET NULL',
1269 { key => 'listprice',
1270 foreigntable => 'currency',
1271 foreignkey => 'currency',
1272 onUpdate => 'CASCADE',
1273 onDelete => 'CASCADE',
1275 { key => 'invoiceprice',
1276 foreigntable => 'currency',
1277 foreignkey => 'currency',
1278 onUpdate => 'CASCADE',
1279 onDelete => 'CASCADE',
1282 aqorderbreakdown => [
1283 { key => 'ordernumber',
1284 foreigntable => 'aqorders',
1285 foreignkey => 'ordernumber',
1286 onUpdate => 'CASCADE',
1287 onDelete => 'CASCADE',
1289 { key => 'bookfundid',
1290 foreigntable => 'aqbookfund',
1291 foreignkey => 'bookfundid',
1292 onUpdate => 'CASCADE',
1293 onDelete => 'CASCADE',
1296 branchtransfers => [
1297 { key => 'frombranch',
1298 foreigntable => 'branches',
1299 foreignkey => 'branchcode',
1300 onUpdate => 'CASCADE',
1301 onDelete => 'CASCADE',
1303 { key => 'tobranch',
1304 foreigntable => 'branches',
1305 foreignkey => 'branchcode',
1306 onUpdate => 'CASCADE',
1307 onDelete => 'CASCADE',
1309 { key => 'itemnumber',
1310 foreigntable => 'items',
1311 foreignkey => 'itemnumber',
1312 onUpdate => 'CASCADE',
1313 onDelete => 'CASCADE',
1317 { key => 'categorycode',
1318 foreigntable => 'categories',
1319 foreignkey => 'categorycode',
1320 onUpdate => 'CASCADE',
1321 onDelete => 'CASCADE',
1323 { key => 'itemtype',
1324 foreigntable => 'itemtypes',
1325 foreignkey => 'itemtype',
1326 onUpdate => 'CASCADE',
1327 onDelete => 'CASCADE',
1330 issues => [ # constraint is SET NULL : when a borrower or an item is deleted, we keep the issuing record
1332 { key => 'borrowernumber',
1333 foreigntable => 'borrowers',
1334 foreignkey => 'borrowernumber',
1335 onUpdate => 'SET NULL',
1336 onDelete => 'SET NULL',
1338 { key => 'itemnumber',
1339 foreigntable => 'items',
1340 foreignkey => 'itemnumber',
1341 onUpdate => 'SET NULL',
1342 onDelete => 'SET NULL',
1346 { key => 'borrowernumber',
1347 foreigntable => 'borrowers',
1348 foreignkey => 'borrowernumber',
1349 onUpdate => 'CASCADE',
1350 onDelete => 'CASCADE',
1352 { key => 'biblionumber',
1353 foreigntable => 'biblio',
1354 foreignkey => 'biblionumber',
1355 onUpdate => 'CASCADE',
1356 onDelete => 'CASCADE',
1358 { key => 'itemnumber',
1359 foreigntable => 'items',
1360 foreignkey => 'itemnumber',
1361 onUpdate => 'CASCADE',
1362 onDelete => 'CASCADE',
1364 { key => 'branchcode',
1365 foreigntable => 'branches',
1366 foreignkey => 'branchcode',
1367 onUpdate => 'CASCADE',
1368 onDelete => 'CASCADE',
1371 borrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1372 # but prevent deleting a branch as soon as it has 1 borrower !
1373 { key => 'categorycode',
1374 foreigntable => 'categories',
1375 foreignkey => 'categorycode',
1376 onUpdate => 'RESTRICT',
1377 onDelete => 'RESTRICT',
1379 { key => 'branchcode',
1380 foreigntable => 'branches',
1381 foreignkey => 'branchcode',
1382 onUpdate => 'RESTRICT',
1383 onDelete => 'RESTRICT',
1386 deletedborrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1387 # but prevent deleting a branch as soon as it has 1 borrower !
1388 { key => 'categorycode',
1389 foreigntable => 'categories',
1390 foreignkey => 'categorycode',
1391 onUpdate => 'RESTRICT',
1392 onDelete => 'RESTRICT',
1394 { key => 'branchcode',
1395 foreigntable => 'branches',
1396 foreignkey => 'branchcode',
1397 onUpdate => 'RESTRICT',
1398 onDelete => 'RESTRICT',
1402 { key => 'borrowernumber',
1403 foreigntable => 'borrowers',
1404 foreignkey => 'borrowernumber',
1405 onUpdate => 'CASCADE',
1406 onDelete => 'CASCADE',
1408 { key => 'itemnumber',
1409 foreigntable => 'items',
1410 foreignkey => 'itemnumber',
1411 onUpdate => 'SET NULL',
1412 onDelete => 'SET NULL',
1415 auth_tag_structure => [
1416 { key => 'authtypecode',
1417 foreigntable => 'auth_types',
1418 foreignkey => 'authtypecode',
1419 onUpdate => 'CASCADE',
1420 onDelete => 'CASCADE',
1423 # FIXME : don't constraint auth_*_table and auth_word, as they may be replaced by zebra
1428 my %column_change = (
1432 from => 'emailaddress',
1437 from => 'streetaddress',
1439 after => 'initials',
1442 from => 'faxnumber',
1447 from => 'textmessaging',
1453 to => 'contactnote',
1454 after => 'opacnote',
1457 from => 'physstreet',
1462 from => 'streetcity',
1464 after => 'B_address',
1477 from => 'homezipcode',
1484 after => 'B_zipcode',
1489 after => 'dateenrolled',
1492 from => 'guarantor',
1493 to => 'guarantorid',
1494 after => 'contactname',
1497 from => 'altrelationship',
1498 to => 'relationship',
1499 after => 'borrowernotes',
1503 deletedborrowers => [
1505 from => 'emailaddress',
1510 from => 'streetaddress',
1512 after => 'initials',
1515 from => 'faxnumber',
1520 from => 'textmessaging',
1526 to => 'contactnote',
1527 after => 'opacnote',
1530 from => 'physstreet',
1535 from => 'streetcity',
1537 after => 'B_address',
1550 from => 'homezipcode',
1557 after => 'B_zipcode',
1562 after => 'dateenrolled',
1565 from => 'guarantor',
1566 to => 'guarantorid',
1567 after => 'contactname',
1570 from => 'altrelationship',
1571 to => 'relationship',
1572 after => 'borrowernotes',
1578 # MOVE all tables TO UTF-8 and innoDB
1579 $sth = $dbh->prepare("show table status");
1581 while ( my $table = $sth->fetchrow_hashref ) {
1582 next if $table->{Name} eq 'marc_word';
1583 next if $table->{Name} eq 'marc_subfield_table';
1584 next if $table->{Name} eq 'auth_word';
1585 next if $table->{Name} eq 'auth_subfield_table';
1586 if ($table->{Engine} ne 'InnoDB') {
1587 $dbh->do("ALTER TABLE $table->{Name} TYPE = innodb");
1588 print "moving $table->{Name} to InnoDB\n";
1590 unless ($table->{Collation} =~ /^utf8/) {
1591 print "moving $table->{Name} to utf8\n";
1592 $dbh->do("ALTER TABLE $table->{Name} CONVERT TO CHARACTER SET utf8");
1593 $dbh->do("ALTER TABLE $table->{Name} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
1594 # 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 !
1600 foreach my $table (keys %column_change) {
1601 $sth = $dbh->prepare("show columns from $table");
1604 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1606 $types{$column}->{type} ="$type";
1607 $types{$column}->{null} = "$null";
1608 $types{$column}->{key} = "$key";
1609 $types{$column}->{default} = "$default";
1610 $types{$column}->{extra} = "$extra";
1612 my $tablerows = $column_change{$table};
1613 foreach my $row ( @$tablerows ) {
1614 if ($types{$row->{from}}->{type}) {
1615 print "altering $table $row->{from} to $row->{to}\n";
1616 # ALTER TABLE `borrowers` CHANGE `faxnumber` `fax` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
1617 # alter table `borrowers` change `faxnumber` `fax` type text null after phone
1619 "alter table `$table` change `$row->{from}` `$row->{to}` $types{$row->{from}}->{type} ".
1620 ($types{$row->{from}}->{null} eq 'YES'?" NULL":" NOT NULL").
1621 ($types{$row->{from}}->{default}?" default ".$types{$row->{from}}->{default}:"").
1622 "$types{$row->{from}}->{extra} after $row->{after} ";
1629 # Enter here the field you want to delete from DB.
1630 # FIXME :: there is a %uselessfield before which seems doing the same things.
1631 my %fieldtodelete = (
1632 # tablename => [fieldname1,fieldname2,...]
1636 print "removing some unused fields...\n";
1637 foreach my $table ( keys %fieldtodelete ) {
1638 foreach my $field ( @{$fieldtodelete{$table}} ){
1639 print "removing ".$field." from ".$table;
1640 my $sth = $dbh->prepare("ALTER TABLE $table DROP $field");
1643 print "Error : $sth->errstr \n";
1648 # Enter here the line you want to remove from DB.
1649 my %linetodelete = (
1650 # table name => where clause.
1651 userflags => "bit = 8", # delete the 'reserveforself' flags
1655 #-------------------
1660 # Get version of MySQL database engine.
1661 my $mysqlversion = `mysqld --version`;
1662 $mysqlversion =~ /Ver (\S*) /;
1664 if ( $mysqlversion ge '3.23' ) {
1665 print "Could convert to MyISAM database tables...\n" unless $silent;
1668 #---------------------------------
1671 # Collect all tables into a list
1672 $sth = $dbh->prepare("show tables");
1674 while ( my ($table) = $sth->fetchrow ) {
1675 $existingtables{$table} = 1;
1679 # Now add any missing tables
1680 foreach $table ( keys %requiretables ) {
1681 unless ( $existingtables{$table} ) {
1682 print "Adding $table table...\n" unless $silent;
1683 my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1686 print "Error : $sth->errstr \n";
1692 #---------------------------------
1695 foreach $table ( keys %requirefields ) {
1696 print "Check table $table\n" if $debug and not $silent;
1697 $sth = $dbh->prepare("show columns from $table");
1700 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1702 $types{$column} = $type;
1704 foreach $column ( keys %{ $requirefields{$table} } ) {
1705 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
1706 if ( !$types{$column} ) {
1708 # column doesn't exist
1709 print "Adding $column field to $table table...\n" unless $silent;
1710 $query = "alter table $table
1711 add column $column " . $requirefields{$table}->{$column};
1712 print "Execute: $query\n" if $debug;
1713 my $sti = $dbh->prepare($query);
1716 print "**Error : $sti->errstr \n";
1723 foreach $table ( keys %fielddefinitions ) {
1724 print "Check table $table\n" if $debug;
1725 $sth = $dbh->prepare("show columns from $table");
1728 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1730 $definitions->{$column}->{type} = $type;
1731 $definitions->{$column}->{null} = $null;
1732 $definitions->{$column}->{null} = 'NULL' if $null eq 'YES';
1733 $definitions->{$column}->{key} = $key;
1734 $definitions->{$column}->{default} = $default;
1735 $definitions->{$column}->{extra} = $extra;
1737 my $fieldrow = $fielddefinitions{$table};
1738 foreach my $row (@$fieldrow) {
1739 my $field = $row->{field};
1740 my $type = $row->{type};
1741 my $null = $row->{null};
1742 # $null = 'YES' if $row->{null} eq 'NULL';
1743 my $key = $row->{key};
1744 my $default = $row->{default};
1745 # $default="''" unless $default;
1746 my $extra = $row->{extra};
1747 my $def = $definitions->{$field};
1748 my $after = ($row->{after}?" after ".$row->{after}:"");
1750 unless ( $type eq $def->{type}
1751 && $null eq $def->{null}
1752 && $key eq $def->{key}
1753 && $extra eq $def->{extra} )
1755 if ( $null eq '' ) {
1758 if ( $key eq 'PRI' ) {
1759 $key = 'PRIMARY KEY';
1761 unless ( $extra eq 'auto_increment' ) {
1765 # if it's a new column use "add", if it's an old one, use "change".
1767 if ($definitions->{$field}->{type}) {
1768 $action="change $field"
1772 # if it's a primary key, drop the previous pk, before altering the table
1773 print " alter or create $field in $table\n" unless $silent;
1775 if ($key ne 'PRIMARY KEY') {
1776 # warn "alter table $table $action $field $type $null $key $extra default $default $after";
1777 $query = "alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1779 # warn "alter table $table drop primary key, $action $field $type $null $key $extra default $default $after";
1780 # something strange : for indexes UNIQUE, they are reported as primary key here.
1781 # but if you try to run with drop primary key, it fails.
1782 # thus, we run the query twice, one will fail, one will succeed.
1784 $query="alter table $table drop primary key, $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1785 $query="alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1792 print "removing some unused data...\n";
1793 foreach my $table ( keys %linetodelete ) {
1794 foreach my $where ( @{linetodelete{$table}} ){
1795 print "DELETE FROM ".$table." where ".$where;
1797 my $sth = $dbh->prepare("DELETE FROM $table where $where");
1800 print "Error : $sth->errstr \n";
1805 # Populate tables with required data
1807 # synch table and deletedtable.
1808 foreach my $table (('borrowers','items','biblio','biblioitems')) {
1809 my %deletedborrowers;
1810 print "synch'ing $table and deleted$table\n";
1811 $sth = $dbh->prepare("show columns from deleted$table");
1813 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1814 $deletedborrowers{$column}=1;
1816 $sth = $dbh->prepare("show columns from $table");
1819 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1820 unless ($deletedborrowers{$column}) {
1821 my $newcol="alter table deleted$table add $column $type";
1822 if ($null eq 'YES') {
1823 $newcol .= " NULL ";
1825 $newcol .= " NOT NULL ";
1827 $newcol .= "default ".$dbh->quote($default) if $default;
1828 $newcol .= " after $previous" if $previous;
1830 print "creating column $column\n";
1836 # update publisheddate
1838 $sth = $dbh->prepare("select count(*) from serial where publisheddate is NULL");
1840 my ($emptypublished) = $sth->fetchrow;
1841 if ($emptypublished) {
1842 print "Updating publisheddate\n";
1843 $dbh->do("update serial set publisheddate=planneddate where publisheddate is NULL");
1845 foreach my $table ( keys %tabledata ) {
1846 print "Checking for data required in table $table...\n" unless $silent;
1847 my $tablerows = $tabledata{$table};
1848 foreach my $row (@$tablerows) {
1849 my $uniquefieldrequired = $row->{uniquefieldrequired};
1850 my $uniquevalue = $row->{$uniquefieldrequired};
1851 my $forceupdate = $row->{forceupdate};
1854 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1856 $sth->execute($uniquevalue);
1858 foreach my $field (keys %$forceupdate) {
1859 if ($forceupdate->{$field}) {
1860 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1861 $sth->execute($row->{$field}, $uniquevalue);
1865 print "Adding row to $table: " unless $silent;
1869 foreach my $field ( keys %$row ) {
1870 next if $field eq 'uniquefieldrequired';
1871 next if $field eq 'forceupdate';
1872 my $value = $row->{$field};
1873 push @values, $value;
1874 print " $field => $value" unless $silent;
1875 $fieldlist .= "$field,";
1876 $placeholders .= "?,";
1878 print "\n" unless $silent;
1879 $fieldlist =~ s/,$//;
1880 $placeholders =~ s/,$//;
1881 print "insert into $table ($fieldlist) values ($placeholders)";
1884 "insert into $table ($fieldlist) values ($placeholders)");
1885 $sth->execute(@values);
1891 # check indexes and create them when needed
1893 print "Checking for index required...\n" unless $silent;
1894 foreach my $table ( keys %indexes ) {
1896 # read all indexes from $table
1898 $sth = $dbh->prepare("show index from $table");
1900 my %existingindexes;
1901 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow ) {
1902 $existingindexes{$key_name} = 1;
1904 # read indexes to check
1905 my $tablerows = $indexes{$table};
1906 foreach my $row (@$tablerows) {
1907 my $key_name=$row->{indexname};
1908 if ($existingindexes{$key_name} eq 1) {
1909 # print "$key_name existing";
1911 print "\tCreating index $key_name in $table\n";
1913 if ($row->{indexname} eq 'PRIMARY') {
1914 $sql = "alter table $table ADD PRIMARY KEY ($row->{content})";
1916 $sql = "alter table $table ADD INDEX $key_name ($row->{content}) $row->{type}";
1919 print "Error $sql : $dbh->err \n" if $dbh->err;
1925 # check foreign keys and create them when needed
1927 print "Checking for foreign keys required...\n" unless $silent;
1928 foreach my $table ( keys %foreign_keys ) {
1930 # read all indexes from $table
1932 $sth = $dbh->prepare("show table status like '$table'");
1934 my $stat = $sth->fetchrow_hashref;
1935 # read indexes to check
1936 my $tablerows = $foreign_keys{$table};
1937 foreach my $row (@$tablerows) {
1938 my $foreign_table=$row->{foreigntable};
1939 if ($stat->{'Comment'} =~/$foreign_table/) {
1940 # print "$foreign_table existing\n";
1942 print "\tCreating foreign key $foreign_table in $table\n";
1943 # first, drop any orphan value in child table
1944 if ($row->{onDelete} ne "RESTRICT") {
1945 my $sql = "delete from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})";
1947 print "SQL ERROR: $sql : $dbh->err \n" if $dbh->err;
1949 my $sql="alter table $table ADD FOREIGN KEY $row->{key} ($row->{key}) REFERENCES $row->{foreigntable} ($row->{foreignkey})";
1950 $sql .= " on update ".$row->{onUpdate} if $row->{onUpdate};
1951 $sql .= " on delete ".$row->{onDelete} if $row->{onDelete};
1954 print "====================
1955 An error occured during :
1957 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).
1958 You can find those values with select
1959 \t$table.* from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})
1960 ====================\n
1966 # now drop useless tables
1967 foreach $table ( @TableToDelete ) {
1968 if ( $existingtables{$table} ) {
1969 print "Dropping unused table $table\n" if $debug and not $silent;
1970 $dbh->do("drop table $table");
1972 print "Error : $dbh->errstr \n";
1981 # create frameworkcode row in biblio table & fill it with marc_biblio.frameworkcode.
1984 # 1st, get how many biblio we will have to do...
1985 $sth = $dbh->prepare('select count(*) from marc_biblio');
1987 my ($totaltodo) = $sth->fetchrow;
1989 $sth = $dbh->prepare("show columns from biblio");
1992 my $bibliofwexist=0;
1993 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
1994 $bibliofwexist=1 if $column eq 'frameworkcode';
1996 unless ($bibliofwexist) {
1997 print "moving biblioframework to biblio table\n";
1998 $dbh->do('ALTER TABLE `biblio` ADD `frameworkcode` VARCHAR( 4 ) NOT NULL AFTER `biblionumber`');
1999 $sth = $dbh->prepare('select biblionumber,frameworkcode from marc_biblio');
2001 my $sth_update = $dbh->prepare('update biblio set frameworkcode=? where biblionumber=?');
2003 while (my ($biblionumber,$frameworkcode) = $sth->fetchrow) {
2004 $sth_update->execute($frameworkcode,$biblionumber);
2006 print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
2011 # at last, remove useless fields
2012 foreach $table ( keys %uselessfields ) {
2013 my @fields = split /,/,$uselessfields{$table};
2016 foreach my $fieldtodrop (@fields) {
2017 $fieldtodrop =~ s/\t//g;
2018 $fieldtodrop =~ s/\n//g;
2020 $sth = $dbh->prepare("show columns from $table");
2022 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
2024 $exists =1 if ($column eq $fieldtodrop);
2027 print "deleting $fieldtodrop field in $table...\n" unless $silent;
2028 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
2035 # Changing aqbookfund's primary key
2037 $sth=$dbh->prepare("ALTER TABLE `aqbookfund` DROP PRIMARY KEY , ADD PRIMARY KEY ( `bookfundid` , `branchcode` ) ;");
2045 # Revision 1.166 2007/06/08 09:40:12 toins
2046 # bug fix : items.homebranch must be VARCHAR(10)
2048 # Revision 1.165 2007/05/23 16:33:10 tipaul
2049 # skip move to innoDB for the 4 22 tables, that are used to store MARC records, are useless in Koha 3.0 The process is very very long, so the updatedatabase should speed up a lot (by long I mean 1 hour on my Dual core with SCSI disk, for a 50 000 biblios long table
2051 # Revision 1.164 2007/05/04 16:24:09 tipaul
2052 # various bugfixes on parameters modules + adding default NoZebraIndexes systempreference if it's empty
2054 # Revision 1.163 2007/05/02 16:44:31 tipaul
2055 # NoZebra SQL index management :
2056 # * adding 3 subs in Biblio.pm
2057 # - GetNoZebraIndexes, that get the index structure in a new systempreference (added with this commit)
2058 # - _DelBiblioNoZebra, that retrieve all index entries for a biblio and remove in a variable the biblio reference
2059 # - _AddBiblioNoZebra, that add index entries for a biblio.
2060 # Note that the 2 _Add and _Del subs work only in a hash variable, to speed up things in case of a modif (ie : delete+add). The effective SQL update is done in the ModZebra sub (that existed before, and dealed with zebra index).
2061 # I think the code has to be more deeply tested, but it works at least partially.
2063 # Revision 1.162 2007/04/30 16:16:50 tipaul
2064 # bugfix for updatedatabase : when there is no default value (NULL fields) + removing bibliothesaurus table+adding NoZebra systempref (False by default)
2066 # Revision 1.161 2007/04/13 16:27:55 hdl
2067 # Adding Version variable to systempreferences.
2069 # Revision 1.160 2007/03/19 18:35:13 toins
2070 # - adding default value in marc_subfield_structure.
2071 # - now marc_subfields_structure displays subfields in tab view.
2073 # Revision 1.159 2007/03/16 01:25:09 kados
2074 # Using my precrash CVS copy I did the following:
2076 # cvs -z3 -d:ext:kados@cvs.savannah.nongnu.org:/sources/koha co -P koha
2077 # find koha.precrash -type d -name "CVS" -exec rm -v {} \;
2078 # cp -r koha.precrash/* koha/
2082 # This should in theory put us right back where we were before the crash
2084 # Revision 1.159 2007/03/12 17:52:30 rych
2085 # add pri key to userflags
2087 # Revision 1.158 2007/03/09 15:14:57 tipaul
2088 # rel_3_0 moved to HEAD
2090 # Revision 1.157.2.56 2007/01/31 16:22:54 btoumi
2091 # -add possibility to use isbn with length of 13 characters
2092 # for Import datas in the reservoir.
2093 # -modify isbn field in marc_breeding table (varchar 13)
2094 # -add isbn filter (no - )when u read a notice from reservoir
2095 # -add filter to have right field 100
2097 # Revision 1.157.2.55 2007/01/30 10:50:19 tipaul
2098 # adding 2 usefull indexes to biblioitems table
2100 # Revision 1.157.2.54 2007/01/29 16:45:52 toins
2101 # * adding a new default authorised value : SUGGEST.
2102 # SUGGEST give some reasons to accept or reject a suggestion.
2104 # * default value for borrowersMandatoryfield syspref is now "cardnumber|surname|adress"
2106 # Revision 1.157.2.53 2007/01/26 20:48:37 hdl
2107 # Serials management : Bugfixes + improvements.
2108 # - Partial dates are now managed
2109 # - next Date Calculation with irregularity tested for 1 week and 1 month.
2110 # - manage if subscription is abouttoexpire or expired.
2111 # - Adding some information on serials pages about subscription.
2112 # - Managing irregularity with numbers.
2113 # - Adding Internal Notes in subscription management.
2114 # - Repeating Button above pages.
2116 # Please run Updatedatabase to change irregularity and add internalnotes field to subscription
2118 # Revision 1.157.2.52 2007/01/24 13:57:26 tipaul
2119 # - setting supplierid to auto_increment (HDL : could you check that is works, i'm not 100% sure)
2120 # - removing 22 -> 30 marc_subfield_table -> marcxml stuff, it's now in misc/migration_tools/22_to_30/
2122 # Revision 1.157.2.51 2007/01/18 09:58:45 tipaul
2123 # defaulting NOT NULL fields (to '')
2125 # Revision 1.157.2.50 2007/01/18 09:39:21 tipaul
2126 # issuedate must be defaulted with ' '
2128 # Revision 1.157.2.49 2007/01/18 09:37:30 tipaul
2129 # removing 2 field definitions that were here twice
2131 # Revision 1.157.2.48 2007/01/15 09:55:40 toins
2132 # adding a new logging systempref : FinesLog.
2134 # Revision 1.157.2.47 2007/01/12 18:09:49 toins
2137 # Revision 1.157.2.46 2007/01/11 14:35:39 tipaul
2138 # adding Opac Browser feature : the build_browser_and_cloud.pl script will :
2139 # - fill the browser table, that enable browsing, digit by digit of a given category, the catalogue. A complete dewey classification is provided in the script, active only for french libraries, of course (although, for instance, the script check that the catalogue is in english for developping convenience)
2140 # - fill the tags table, that contains the subject cloud.
2142 # The cloud part is a copy of the previous build_tags.pl script that can be deleted : those 2 scripts require to parse all the catalogue to extract interesting data, so they are long. It's useless to parse the catalogue twice !
2144 # The commit also add the systempreference to hide/show the OpacBrowse in database & in systempref management script.
2146 # IMPROVEMENTS to do :
2147 # - the script that builds the tables can be improved to update only last week biblios (at the price of a small error in value links, but it's not a problem).
2148 # - add, in parameters section, a place to edit browser descriptions. The build script has to be updated to to avoid deleting existing browser descriptions.
2150 # Revision 1.157.2.45 2007/01/10 16:52:52 toins
2151 # Value for Log Features syspref are set to 0 by default.
2153 # Revision 1.157.2.44 2007/01/10 16:31:15 toins
2154 # new systems preferences :
2155 # - CataloguingLog (log the update/creation/deletion of a notice if set to 1)
2156 # - BorrowersLog ( idem for borrowers )
2157 # - IssueLog (log all issue if set to 1)
2158 # - ReturnLog (log all return if set to 1)
2159 # - SusbcriptionLog (log all creation/deletion/update of a subcription)
2161 # All of theses are in a new tab called 'LOGFeatures' in systempreferences.pl
2163 # Revision 1.157.2.43 2007/01/10 14:13:17 toins
2164 # opac_news.displayed is replaced by opac_news.number.
2165 # This field say how are ordered the news on the template.
2167 # Revision 1.157.2.42 2007/01/09 14:09:01 toins
2168 # 2 field added to opac_news.('expirationdate' and 'displayed').