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 enoug 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 => 'holdingbranch',
945 type => 'varchar(10)',
953 type => 'varchar(10)',
963 type => 'varchar(10)',
977 marc_subfield_structure => [
979 field => 'defaultvalue',
988 field => 'expirationdate',
1005 field => 'waitingdate',
1025 field => 'dateadded',
1026 type => 'timestamp',
1030 systempreferences => [
1040 field => 'explanation',
1062 # { indexname => 'index detail'
1066 { indexname => 'PRIMARY',
1072 { indexname => 'booksellerid',
1073 content => 'booksellerid',
1077 { indexname => 'basketno',
1078 content => 'basketno',
1081 aqorderbreakdown => [
1082 { indexname => 'ordernumber',
1083 content => 'ordernumber',
1085 { indexname => 'bookfundid',
1086 content => 'bookfundid',
1090 { indexname => 'isbn',
1093 { indexname => 'publishercode',
1094 content => 'publishercode',
1099 indexname => 'branchcode',
1100 content => 'branchcode',
1105 { indexname => 'PRIMARY',
1106 content => 'currency',
1112 indexname => 'categorycode',
1113 content => 'categorycode',
1117 { indexname => 'homebranch',
1118 content => 'homebranch',
1120 { indexname => 'holdingbranch',
1121 content => 'holdingbranch',
1126 indexname => 'itemtype',
1127 content => 'itemtype',
1131 { indexname => 'shelfnumber',
1132 content => 'shelfnumber',
1134 { indexname => 'itemnumber',
1135 content => 'itemnumber',
1139 { indexname => 'PRIMARY',
1146 my %foreign_keys = (
1148 # { key => 'the key in table' (must be indexed)
1149 # foreigntable => 'the foreigntable name', # (the parent)
1150 # foreignkey => 'the foreign key column(s)' # (in the parent)
1151 # onUpdate => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1152 # onDelete => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
1156 { key => 'shelfnumber',
1157 foreigntable => 'bookshelf',
1158 foreignkey => 'shelfnumber',
1159 onUpdate => 'CASCADE',
1160 onDelete => 'CASCADE',
1162 { key => 'itemnumber',
1163 foreigntable => 'items',
1164 foreignkey => 'itemnumber',
1165 onUpdate => 'CASCADE',
1166 onDelete => 'CASCADE',
1169 # onDelete is RESTRICT on reference tables (branches, itemtype) as we don't want items to be
1170 # easily deleted, but branches/itemtype not too easy to empty...
1172 { key => 'biblionumber',
1173 foreigntable => 'biblio',
1174 foreignkey => 'biblionumber',
1175 onUpdate => 'CASCADE',
1176 onDelete => 'CASCADE',
1178 { key => 'itemtype',
1179 foreigntable => 'itemtypes',
1180 foreignkey => 'itemtype',
1181 onUpdate => 'CASCADE',
1182 onDelete => 'RESTRICT',
1186 { key => 'biblioitemnumber',
1187 foreigntable => 'biblioitems',
1188 foreignkey => 'biblioitemnumber',
1189 onUpdate => 'CASCADE',
1190 onDelete => 'CASCADE',
1192 { key => 'homebranch',
1193 foreigntable => 'branches',
1194 foreignkey => 'branchcode',
1195 onUpdate => 'CASCADE',
1196 onDelete => 'RESTRICT',
1198 { key => 'holdingbranch',
1199 foreigntable => 'branches',
1200 foreignkey => 'branchcode',
1201 onUpdate => 'CASCADE',
1202 onDelete => 'RESTRICT',
1206 { key => 'booksellerid',
1207 foreigntable => 'aqbooksellers',
1209 onUpdate => 'CASCADE',
1210 onDelete => 'RESTRICT',
1214 { key => 'basketno',
1215 foreigntable => 'aqbasket',
1216 foreignkey => 'basketno',
1217 onUpdate => 'CASCADE',
1218 onDelete => 'CASCADE',
1220 { key => 'biblionumber',
1221 foreigntable => 'biblio',
1222 foreignkey => 'biblionumber',
1223 onUpdate => 'SET NULL',
1224 onDelete => 'SET NULL',
1228 { key => 'listprice',
1229 foreigntable => 'currency',
1230 foreignkey => 'currency',
1231 onUpdate => 'CASCADE',
1232 onDelete => 'CASCADE',
1234 { key => 'invoiceprice',
1235 foreigntable => 'currency',
1236 foreignkey => 'currency',
1237 onUpdate => 'CASCADE',
1238 onDelete => 'CASCADE',
1241 aqorderbreakdown => [
1242 { key => 'ordernumber',
1243 foreigntable => 'aqorders',
1244 foreignkey => 'ordernumber',
1245 onUpdate => 'CASCADE',
1246 onDelete => 'CASCADE',
1248 { key => 'bookfundid',
1249 foreigntable => 'aqbookfund',
1250 foreignkey => 'bookfundid',
1251 onUpdate => 'CASCADE',
1252 onDelete => 'CASCADE',
1255 branchtransfers => [
1256 { key => 'frombranch',
1257 foreigntable => 'branches',
1258 foreignkey => 'branchcode',
1259 onUpdate => 'CASCADE',
1260 onDelete => 'CASCADE',
1262 { key => 'tobranch',
1263 foreigntable => 'branches',
1264 foreignkey => 'branchcode',
1265 onUpdate => 'CASCADE',
1266 onDelete => 'CASCADE',
1268 { key => 'itemnumber',
1269 foreigntable => 'items',
1270 foreignkey => 'itemnumber',
1271 onUpdate => 'CASCADE',
1272 onDelete => 'CASCADE',
1276 { key => 'categorycode',
1277 foreigntable => 'categories',
1278 foreignkey => 'categorycode',
1279 onUpdate => 'CASCADE',
1280 onDelete => 'CASCADE',
1282 { key => 'itemtype',
1283 foreigntable => 'itemtypes',
1284 foreignkey => 'itemtype',
1285 onUpdate => 'CASCADE',
1286 onDelete => 'CASCADE',
1289 issues => [ # constraint is SET NULL : when a borrower or an item is deleted, we keep the issuing record
1291 { key => 'borrowernumber',
1292 foreigntable => 'borrowers',
1293 foreignkey => 'borrowernumber',
1294 onUpdate => 'SET NULL',
1295 onDelete => 'SET NULL',
1297 { key => 'itemnumber',
1298 foreigntable => 'items',
1299 foreignkey => 'itemnumber',
1300 onUpdate => 'SET NULL',
1301 onDelete => 'SET NULL',
1305 { key => 'borrowernumber',
1306 foreigntable => 'borrowers',
1307 foreignkey => 'borrowernumber',
1308 onUpdate => 'CASCADE',
1309 onDelete => 'CASCADE',
1311 { key => 'biblionumber',
1312 foreigntable => 'biblio',
1313 foreignkey => 'biblionumber',
1314 onUpdate => 'CASCADE',
1315 onDelete => 'CASCADE',
1317 { key => 'itemnumber',
1318 foreigntable => 'items',
1319 foreignkey => 'itemnumber',
1320 onUpdate => 'CASCADE',
1321 onDelete => 'CASCADE',
1323 { key => 'branchcode',
1324 foreigntable => 'branches',
1325 foreignkey => 'branchcode',
1326 onUpdate => 'CASCADE',
1327 onDelete => 'CASCADE',
1330 borrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1331 # but prevent deleting a branch as soon as it has 1 borrower !
1332 { key => 'categorycode',
1333 foreigntable => 'categories',
1334 foreignkey => 'categorycode',
1335 onUpdate => 'RESTRICT',
1336 onDelete => 'RESTRICT',
1338 { key => 'branchcode',
1339 foreigntable => 'branches',
1340 foreignkey => 'branchcode',
1341 onUpdate => 'RESTRICT',
1342 onDelete => 'RESTRICT',
1345 deletedborrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
1346 # but prevent deleting a branch as soon as it has 1 borrower !
1347 { key => 'categorycode',
1348 foreigntable => 'categories',
1349 foreignkey => 'categorycode',
1350 onUpdate => 'RESTRICT',
1351 onDelete => 'RESTRICT',
1353 { key => 'branchcode',
1354 foreigntable => 'branches',
1355 foreignkey => 'branchcode',
1356 onUpdate => 'RESTRICT',
1357 onDelete => 'RESTRICT',
1361 { key => 'borrowernumber',
1362 foreigntable => 'borrowers',
1363 foreignkey => 'borrowernumber',
1364 onUpdate => 'CASCADE',
1365 onDelete => 'CASCADE',
1367 { key => 'itemnumber',
1368 foreigntable => 'items',
1369 foreignkey => 'itemnumber',
1370 onUpdate => 'SET NULL',
1371 onDelete => 'SET NULL',
1374 auth_tag_structure => [
1375 { key => 'authtypecode',
1376 foreigntable => 'auth_types',
1377 foreignkey => 'authtypecode',
1378 onUpdate => 'CASCADE',
1379 onDelete => 'CASCADE',
1382 # FIXME : don't constraint auth_*_table and auth_word, as they may be replaced by zebra
1387 my %column_change = (
1391 from => 'emailaddress',
1396 from => 'streetaddress',
1398 after => 'initials',
1401 from => 'faxnumber',
1406 from => 'textmessaging',
1412 to => 'contactnote',
1413 after => 'opacnote',
1416 from => 'physstreet',
1421 from => 'streetcity',
1423 after => 'B_address',
1436 from => 'homezipcode',
1443 after => 'B_zipcode',
1448 after => 'dateenrolled',
1451 from => 'guarantor',
1452 to => 'guarantorid',
1453 after => 'contactname',
1456 from => 'altrelationship',
1457 to => 'relationship',
1458 after => 'borrowernotes',
1462 deletedborrowers => [
1464 from => 'emailaddress',
1469 from => 'streetaddress',
1471 after => 'initials',
1474 from => 'faxnumber',
1479 from => 'textmessaging',
1485 to => 'contactnote',
1486 after => 'opacnote',
1489 from => 'physstreet',
1494 from => 'streetcity',
1496 after => 'B_address',
1509 from => 'homezipcode',
1516 after => 'B_zipcode',
1521 after => 'dateenrolled',
1524 from => 'guarantor',
1525 to => 'guarantorid',
1526 after => 'contactname',
1529 from => 'altrelationship',
1530 to => 'relationship',
1531 after => 'borrowernotes',
1537 # MOVE all tables TO UTF-8 and innoDB
1538 $sth = $dbh->prepare("show table status");
1540 while ( my $table = $sth->fetchrow_hashref ) {
1541 if ($table->{Engine} ne 'InnoDB') {
1542 $dbh->do("ALTER TABLE $table->{Name} TYPE = innodb");
1543 print "moving $table->{Name} to InnoDB\n";
1545 next if $table->{Name} eq 'marc_word';
1546 next if $table->{Name} eq 'marc_subfield_table';
1547 next if $table->{Name} eq 'auth_word';
1548 next if $table->{Name} eq 'auth_subfield_table';
1549 unless ($table->{Collation} =~ /^utf8/) {
1550 print "moving $table->{Name} to utf8\n";
1551 $dbh->do("ALTER TABLE $table->{Name} CONVERT TO CHARACTER SET utf8");
1552 $dbh->do("ALTER TABLE $table->{Name} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
1553 # 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 !
1559 foreach my $table (keys %column_change) {
1560 $sth = $dbh->prepare("show columns from $table");
1563 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1565 $types{$column}->{type} ="$type";
1566 $types{$column}->{null} = "$null";
1567 $types{$column}->{key} = "$key";
1568 $types{$column}->{default} = "$default";
1569 $types{$column}->{extra} = "$extra";
1571 my $tablerows = $column_change{$table};
1572 foreach my $row ( @$tablerows ) {
1573 if ($types{$row->{from}}->{type}) {
1574 print "altering $table $row->{from} to $row->{to}\n";
1575 # ALTER TABLE `borrowers` CHANGE `faxnumber` `fax` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
1576 # alter table `borrowers` change `faxnumber` `fax` type text null after phone
1578 "alter table `$table` change `$row->{from}` `$row->{to}` $types{$row->{from}}->{type} ".
1579 ($types{$row->{from}}->{null} eq 'YES'?" NULL":" NOT NULL").
1580 ($types{$row->{from}}->{default}?" default ".$types{$row->{from}}->{default}:"").
1581 "$types{$row->{from}}->{extra} after $row->{after} ";
1588 # Enter here the field you want to delete from DB.
1589 # FIXME :: there is a %uselessfield before which seems doing the same things.
1590 my %fieldtodelete = (
1591 # tablename => [fieldname1,fieldname2,...]
1595 print "removing some unused fields...\n";
1596 foreach my $table ( keys %fieldtodelete ) {
1597 foreach my $field ( @{$fieldtodelete{$table}} ){
1598 print "removing ".$field." from ".$table;
1599 my $sth = $dbh->prepare("ALTER TABLE $table DROP $field");
1602 print "Error : $sth->errstr \n";
1607 # Enter here the line you want to remove from DB.
1608 my %linetodelete = (
1609 # table name => where clause.
1610 userflags => "bit = 8", # delete the 'reserveforself' flags
1614 #-------------------
1619 # Get version of MySQL database engine.
1620 my $mysqlversion = `mysqld --version`;
1621 $mysqlversion =~ /Ver (\S*) /;
1623 if ( $mysqlversion ge '3.23' ) {
1624 print "Could convert to MyISAM database tables...\n" unless $silent;
1627 #---------------------------------
1630 # Collect all tables into a list
1631 $sth = $dbh->prepare("show tables");
1633 while ( my ($table) = $sth->fetchrow ) {
1634 $existingtables{$table} = 1;
1638 # Now add any missing tables
1639 foreach $table ( keys %requiretables ) {
1640 unless ( $existingtables{$table} ) {
1641 print "Adding $table table...\n" unless $silent;
1642 my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1645 print "Error : $sth->errstr \n";
1651 #---------------------------------
1654 foreach $table ( keys %requirefields ) {
1655 print "Check table $table\n" if $debug and not $silent;
1656 $sth = $dbh->prepare("show columns from $table");
1659 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1661 $types{$column} = $type;
1663 foreach $column ( keys %{ $requirefields{$table} } ) {
1664 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
1665 if ( !$types{$column} ) {
1667 # column doesn't exist
1668 print "Adding $column field to $table table...\n" unless $silent;
1669 $query = "alter table $table
1670 add column $column " . $requirefields{$table}->{$column};
1671 print "Execute: $query\n" if $debug;
1672 my $sti = $dbh->prepare($query);
1675 print "**Error : $sti->errstr \n";
1682 foreach $table ( keys %fielddefinitions ) {
1683 print "Check table $table\n" if $debug;
1684 $sth = $dbh->prepare("show columns from $table");
1687 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1689 $definitions->{$column}->{type} = $type;
1690 $definitions->{$column}->{null} = $null;
1691 $definitions->{$column}->{null} = 'NULL' if $null eq 'YES';
1692 $definitions->{$column}->{key} = $key;
1693 $definitions->{$column}->{default} = $default;
1694 $definitions->{$column}->{extra} = $extra;
1696 my $fieldrow = $fielddefinitions{$table};
1697 foreach my $row (@$fieldrow) {
1698 my $field = $row->{field};
1699 my $type = $row->{type};
1700 my $null = $row->{null};
1701 # $null = 'YES' if $row->{null} eq 'NULL';
1702 my $key = $row->{key};
1703 my $default = $row->{default};
1704 # $default="''" unless $default;
1705 my $extra = $row->{extra};
1706 my $def = $definitions->{$field};
1707 my $after = ($row->{after}?" after ".$row->{after}:"");
1709 unless ( $type eq $def->{type}
1710 && $null eq $def->{null}
1711 && $key eq $def->{key}
1712 && $extra eq $def->{extra} )
1714 if ( $null eq '' ) {
1717 if ( $key eq 'PRI' ) {
1718 $key = 'PRIMARY KEY';
1720 unless ( $extra eq 'auto_increment' ) {
1724 # if it's a new column use "add", if it's an old one, use "change".
1726 if ($definitions->{$field}->{type}) {
1727 $action="change $field"
1731 # if it's a primary key, drop the previous pk, before altering the table
1732 print " alter or create $field in $table\n" unless $silent;
1734 if ($key ne 'PRIMARY KEY') {
1735 # warn "alter table $table $action $field $type $null $key $extra default $default $after";
1736 $query = "alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1738 # warn "alter table $table drop primary key, $action $field $type $null $key $extra default $default $after";
1739 # something strange : for indexes UNIQUE, they are reported as primary key here.
1740 # but if you try to run with drop primary key, it fails.
1741 # thus, we run the query twice, one will fail, one will succeed.
1743 $query="alter table $table drop primary key, $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1744 $query="alter table $table $action $field $type $null $key $extra ".($default?"default ".$dbh->quote($default):"")." $after";
1751 print "removing some unused data...\n";
1752 foreach my $table ( keys %linetodelete ) {
1753 foreach my $where ( @{linetodelete{$table}} ){
1754 print "DELETE FROM ".$table." where ".$where;
1756 my $sth = $dbh->prepare("DELETE FROM $table where $where");
1759 print "Error : $sth->errstr \n";
1764 # Populate tables with required data
1766 # synch table and deletedtable.
1767 foreach my $table (('borrowers','items','biblio','biblioitems')) {
1768 my %deletedborrowers;
1769 print "synch'ing $table and deleted$table\n";
1770 $sth = $dbh->prepare("show columns from deleted$table");
1772 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1773 $deletedborrowers{$column}=1;
1775 $sth = $dbh->prepare("show columns from $table");
1778 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1779 unless ($deletedborrowers{$column}) {
1780 my $newcol="alter table deleted$table add $column $type";
1781 if ($null eq 'YES') {
1782 $newcol .= " NULL ";
1784 $newcol .= " NOT NULL ";
1786 $newcol .= "default ".$dbh->quote($default) if $default;
1787 $newcol .= " after $previous" if $previous;
1789 print "creating column $column\n";
1795 # update publisheddate
1797 $sth = $dbh->prepare("select count(*) from serial where publisheddate is NULL");
1799 my ($emptypublished) = $sth->fetchrow;
1800 if ($emptypublished) {
1801 print "Updating publisheddate\n";
1802 $dbh->do("update serial set publisheddate=planneddate where publisheddate is NULL");
1804 foreach my $table ( keys %tabledata ) {
1805 print "Checking for data required in table $table...\n" unless $silent;
1806 my $tablerows = $tabledata{$table};
1807 foreach my $row (@$tablerows) {
1808 my $uniquefieldrequired = $row->{uniquefieldrequired};
1809 my $uniquevalue = $row->{$uniquefieldrequired};
1810 my $forceupdate = $row->{forceupdate};
1813 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1815 $sth->execute($uniquevalue);
1817 foreach my $field (keys %$forceupdate) {
1818 if ($forceupdate->{$field}) {
1819 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1820 $sth->execute($row->{$field}, $uniquevalue);
1824 print "Adding row to $table: " unless $silent;
1828 foreach my $field ( keys %$row ) {
1829 next if $field eq 'uniquefieldrequired';
1830 next if $field eq 'forceupdate';
1831 my $value = $row->{$field};
1832 push @values, $value;
1833 print " $field => $value" unless $silent;
1834 $fieldlist .= "$field,";
1835 $placeholders .= "?,";
1837 print "\n" unless $silent;
1838 $fieldlist =~ s/,$//;
1839 $placeholders =~ s/,$//;
1840 print "insert into $table ($fieldlist) values ($placeholders)";
1843 "insert into $table ($fieldlist) values ($placeholders)");
1844 $sth->execute(@values);
1850 # check indexes and create them when needed
1852 print "Checking for index required...\n" unless $silent;
1853 foreach my $table ( keys %indexes ) {
1855 # read all indexes from $table
1857 $sth = $dbh->prepare("show index from $table");
1859 my %existingindexes;
1860 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow ) {
1861 $existingindexes{$key_name} = 1;
1863 # read indexes to check
1864 my $tablerows = $indexes{$table};
1865 foreach my $row (@$tablerows) {
1866 my $key_name=$row->{indexname};
1867 if ($existingindexes{$key_name} eq 1) {
1868 # print "$key_name existing";
1870 print "\tCreating index $key_name in $table\n";
1872 if ($row->{indexname} eq 'PRIMARY') {
1873 $sql = "alter table $table ADD PRIMARY KEY ($row->{content})";
1875 $sql = "alter table $table ADD INDEX $key_name ($row->{content}) $row->{type}";
1878 print "Error $sql : $dbh->err \n" if $dbh->err;
1884 # check foreign keys and create them when needed
1886 print "Checking for foreign keys required...\n" unless $silent;
1887 foreach my $table ( keys %foreign_keys ) {
1889 # read all indexes from $table
1891 $sth = $dbh->prepare("show table status like '$table'");
1893 my $stat = $sth->fetchrow_hashref;
1894 # read indexes to check
1895 my $tablerows = $foreign_keys{$table};
1896 foreach my $row (@$tablerows) {
1897 my $foreign_table=$row->{foreigntable};
1898 if ($stat->{'Comment'} =~/$foreign_table/) {
1899 # print "$foreign_table existing\n";
1901 print "\tCreating foreign key $foreign_table in $table\n";
1902 # first, drop any orphan value in child table
1903 if ($row->{onDelete} ne "RESTRICT") {
1904 my $sql = "delete from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})";
1906 print "SQL ERROR: $sql : $dbh->err \n" if $dbh->err;
1908 my $sql="alter table $table ADD FOREIGN KEY $row->{key} ($row->{key}) REFERENCES $row->{foreigntable} ($row->{foreignkey})";
1909 $sql .= " on update ".$row->{onUpdate} if $row->{onUpdate};
1910 $sql .= " on delete ".$row->{onDelete} if $row->{onDelete};
1913 print "====================
1914 An error occured during :
1916 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).
1917 You can find those values with select
1918 \t$table.* from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})
1919 ====================\n
1925 # now drop useless tables
1926 foreach $table ( @TableToDelete ) {
1927 if ( $existingtables{$table} ) {
1928 print "Dropping unused table $table\n" if $debug and not $silent;
1929 $dbh->do("drop table $table");
1931 print "Error : $dbh->errstr \n";
1940 # create frameworkcode row in biblio table & fill it with marc_biblio.frameworkcode.
1943 # 1st, get how many biblio we will have to do...
1944 $sth = $dbh->prepare('select count(*) from marc_biblio');
1946 my ($totaltodo) = $sth->fetchrow;
1948 $sth = $dbh->prepare("show columns from biblio");
1951 my $bibliofwexist=0;
1952 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
1953 $bibliofwexist=1 if $column eq 'frameworkcode';
1955 unless ($bibliofwexist) {
1956 print "moving biblioframework to biblio table\n";
1957 $dbh->do('ALTER TABLE `biblio` ADD `frameworkcode` VARCHAR( 4 ) NOT NULL AFTER `biblionumber`');
1958 $sth = $dbh->prepare('select biblionumber,frameworkcode from marc_biblio');
1960 my $sth_update = $dbh->prepare('update biblio set frameworkcode=? where biblionumber=?');
1962 while (my ($biblionumber,$frameworkcode) = $sth->fetchrow) {
1963 $sth_update->execute($frameworkcode,$biblionumber);
1965 print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
1970 # at last, remove useless fields
1971 foreach $table ( keys %uselessfields ) {
1972 my @fields = split /,/,$uselessfields{$table};
1975 foreach my $fieldtodrop (@fields) {
1976 $fieldtodrop =~ s/\t//g;
1977 $fieldtodrop =~ s/\n//g;
1979 $sth = $dbh->prepare("show columns from $table");
1981 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1983 $exists =1 if ($column eq $fieldtodrop);
1986 print "deleting $fieldtodrop field in $table...\n" unless $silent;
1987 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
1994 # Changing aqbookfund's primary key
1996 $sth=$dbh->prepare("ALTER TABLE `aqbookfund` DROP PRIMARY KEY , ADD PRIMARY KEY ( `bookfundid` , `branchcode` ) ;");
2004 # Revision 1.163 2007/05/02 16:44:31 tipaul
2005 # NoZebra SQL index management :
2006 # * adding 3 subs in Biblio.pm
2007 # - GetNoZebraIndexes, that get the index structure in a new systempreference (added with this commit)
2008 # - _DelBiblioNoZebra, that retrieve all index entries for a biblio and remove in a variable the biblio reference
2009 # - _AddBiblioNoZebra, that add index entries for a biblio.
2010 # 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).
2011 # I think the code has to be more deeply tested, but it works at least partially.
2013 # Revision 1.162 2007/04/30 16:16:50 tipaul
2014 # bugfix for updatedatabase : when there is no default value (NULL fields) + removing bibliothesaurus table+adding NoZebra systempref (False by default)
2016 # Revision 1.161 2007/04/13 16:27:55 hdl
2017 # Adding Version variable to systempreferences.
2019 # Revision 1.160 2007/03/19 18:35:13 toins
2020 # - adding default value in marc_subfield_structure.
2021 # - now marc_subfields_structure displays subfields in tab view.
2023 # Revision 1.159 2007/03/16 01:25:09 kados
2024 # Using my precrash CVS copy I did the following:
2026 # cvs -z3 -d:ext:kados@cvs.savannah.nongnu.org:/sources/koha co -P koha
2027 # find koha.precrash -type d -name "CVS" -exec rm -v {} \;
2028 # cp -r koha.precrash/* koha/
2032 # This should in theory put us right back where we were before the crash
2034 # Revision 1.159 2007/03/12 17:52:30 rych
2035 # add pri key to userflags
2037 # Revision 1.158 2007/03/09 15:14:57 tipaul
2038 # rel_3_0 moved to HEAD
2040 # Revision 1.157.2.56 2007/01/31 16:22:54 btoumi
2041 # -add possibility to use isbn with length of 13 characters
2042 # for Import datas in the reservoir.
2043 # -modify isbn field in marc_breeding table (varchar 13)
2044 # -add isbn filter (no - )when u read a notice from reservoir
2045 # -add filter to have right field 100
2047 # Revision 1.157.2.55 2007/01/30 10:50:19 tipaul
2048 # adding 2 usefull indexes to biblioitems table
2050 # Revision 1.157.2.54 2007/01/29 16:45:52 toins
2051 # * adding a new default authorised value : SUGGEST.
2052 # SUGGEST give some reasons to accept or reject a suggestion.
2054 # * default value for borrowersMandatoryfield syspref is now "cardnumber|surname|adress"
2056 # Revision 1.157.2.53 2007/01/26 20:48:37 hdl
2057 # Serials management : Bugfixes + improvements.
2058 # - Partial dates are now managed
2059 # - next Date Calculation with irregularity tested for 1 week and 1 month.
2060 # - manage if subscription is abouttoexpire or expired.
2061 # - Adding some information on serials pages about subscription.
2062 # - Managing irregularity with numbers.
2063 # - Adding Internal Notes in subscription management.
2064 # - Repeating Button above pages.
2066 # Please run Updatedatabase to change irregularity and add internalnotes field to subscription
2068 # Revision 1.157.2.52 2007/01/24 13:57:26 tipaul
2069 # - setting supplierid to auto_increment (HDL : could you check that is works, i'm not 100% sure)
2070 # - removing 22 -> 30 marc_subfield_table -> marcxml stuff, it's now in misc/migration_tools/22_to_30/
2072 # Revision 1.157.2.51 2007/01/18 09:58:45 tipaul
2073 # defaulting NOT NULL fields (to '')
2075 # Revision 1.157.2.50 2007/01/18 09:39:21 tipaul
2076 # issuedate must be defaulted with ' '
2078 # Revision 1.157.2.49 2007/01/18 09:37:30 tipaul
2079 # removing 2 field definitions that were here twice
2081 # Revision 1.157.2.48 2007/01/15 09:55:40 toins
2082 # adding a new logging systempref : FinesLog.
2084 # Revision 1.157.2.47 2007/01/12 18:09:49 toins
2087 # Revision 1.157.2.46 2007/01/11 14:35:39 tipaul
2088 # adding Opac Browser feature : the build_browser_and_cloud.pl script will :
2089 # - 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)
2090 # - fill the tags table, that contains the subject cloud.
2092 # 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 !
2094 # The commit also add the systempreference to hide/show the OpacBrowse in database & in systempref management script.
2096 # IMPROVEMENTS to do :
2097 # - 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).
2098 # - add, in parameters section, a place to edit browser descriptions. The build script has to be updated to to avoid deleting existing browser descriptions.
2100 # Revision 1.157.2.45 2007/01/10 16:52:52 toins
2101 # Value for Log Features syspref are set to 0 by default.
2103 # Revision 1.157.2.44 2007/01/10 16:31:15 toins
2104 # new systems preferences :
2105 # - CataloguingLog (log the update/creation/deletion of a notice if set to 1)
2106 # - BorrowersLog ( idem for borrowers )
2107 # - IssueLog (log all issue if set to 1)
2108 # - ReturnLog (log all return if set to 1)
2109 # - SusbcriptionLog (log all creation/deletion/update of a subcription)
2111 # All of theses are in a new tab called 'LOGFeatures' in systempreferences.pl
2113 # Revision 1.157.2.43 2007/01/10 14:13:17 toins
2114 # opac_news.displayed is replaced by opac_news.number.
2115 # This field say how are ordered the news on the template.
2117 # Revision 1.157.2.42 2007/01/09 14:09:01 toins
2118 # 2 field added to opac_news.('expirationdate' and 'displayed').