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.
15 use lib "/usr/koha200pre2/modules";
24 # FIXME - The user might be installing a new database, so can't rely
25 # on /etc/koha.conf anyway.
32 %existingtables, # tables already in database
36 $type, $null, $key, $default, $extra,
37 $prefitem, # preference item in systempreferences table
44 my $dbh = C4::Context->dbh;
45 print "connected to your DB. Checking & modifying it\n" unless $silent;
50 # Tables to add if they don't exist
52 shelfcontents => "( shelfnumber int not null,
53 itemnumber int not null,
55 bookshelf => "( shelfnumber int auto_increment primary key,
56 shelfname char(255))",
57 z3950queue => "( id int auto_increment primary key,
66 identifier char(30))",
67 z3950results => "( id int auto_increment primary key,
77 branchrelations => "( branchcode varchar(4),
78 categorycode varchar(4))",
79 websites => "( websitenumber int(11) NOT NULL auto_increment,
80 biblionumber int(11) NOT NULL default '0',
84 PRIMARY KEY (websitenumber) )",
85 marcrecorddone => "( isbn char(40),
88 controlnumber char(40))",
89 uploadedmarc => "( id int(11) NOT NULL auto_increment PRIMARY KEY,
91 hidden smallint(6) default NULL,
92 name varchar(255) default NULL)",
93 ethnicity => "( code varchar(10) NOT NULL default '',
94 name varchar(255) default NULL,
95 PRIMARY KEY (code) )",
96 sessions => "( sessionID varchar(255) NOT NULL default '',
97 userid varchar(255) default NULL,
98 ip varchar(16) default NULL,
100 PRIMARY KEY (sessionID) )",
101 sessionqueries => "( sessionID varchar(255) NOT NULL default '',
102 userid char(100) NOT NULL default '',
103 ip char(18) NOT NULL default '',
104 url text NOT NULL default '' )",
105 bibliothesaurus => "( id bigint(20) NOT NULL auto_increment,
106 freelib char(255) NOT NULL default '',
107 stdlib char(255) NOT NULL default '',
108 category char(10) NOT NULL default '',
109 level tinyint(4) NOT NULL default '1',
110 hierarchy char(80) NOT NULL default '',
111 father char(80) NOT NULL default '',
113 KEY freelib (freelib),
115 KEY category (category),
116 KEY hierarchy (hierarchy)
119 bibid bigint(20) unsigned NOT NULL auto_increment,
120 biblionumber int(11) NOT NULL default '0',
121 datecreated date NOT NULL default '0000-00-00',
122 datemodified date default NULL,
123 origincode char(20) default NULL,
125 KEY origincode (origincode),
126 KEY biblionumber (biblionumber)
128 marc_blob_subfield => "(
129 blobidlink bigint(20) NOT NULL auto_increment,
130 subfieldvalue longtext NOT NULL,
131 PRIMARY KEY (blobidlink)
133 marc_subfield_structure => "(
134 tagfield char(3) NOT NULL default '',
135 tagsubfield char(1) NOT NULL default '',
136 liblibrarian char(255) NOT NULL default '',
137 libopac char(255) NOT NULL default '',
138 repeatable tinyint(4) NOT NULL default '0',
139 mandatory tinyint(4) NOT NULL default '0',
140 kohafield char(40) default NULL,
141 tab tinyint(1) default NULL,
142 authorised_value char(10) default NULL,
143 thesaurus_category char(10) default NULL,
144 value_builder char(80) default NULL,
145 PRIMARY KEY (tagfield,tagsubfield),
146 KEY kohafield (kohafield),
149 marc_subfield_table => "(
150 subfieldid bigint(20) unsigned NOT NULL auto_increment,
151 bibid bigint(20) unsigned NOT NULL default '0',
152 tag char(3) NOT NULL default '',
153 tagorder tinyint(4) NOT NULL default '1',
154 tag_indicator char(2) NOT NULL default '',
155 subfieldcode char(1) NOT NULL default '',
156 subfieldorder tinyint(4) NOT NULL default '1',
157 subfieldvalue varchar(255) default NULL,
158 valuebloblink bigint(20) default NULL,
159 PRIMARY KEY (subfieldid),
162 KEY tag_indicator (tag_indicator),
163 KEY subfieldorder (subfieldorder),
164 KEY subfieldcode (subfieldcode),
165 KEY subfieldvalue (subfieldvalue),
166 KEY tagorder (tagorder)
168 marc_tag_structure => "(
169 tagfield char(3) NOT NULL default '',
170 liblibrarian char(255) NOT NULL default '',
171 libopac char(255) NOT NULL default '',
172 repeatable tinyint(4) NOT NULL default '0',
173 mandatory tinyint(4) NOT NULL default '0',
174 authorised_value char(10) default NULL,
175 PRIMARY KEY (tagfield)
178 bibid bigint(20) NOT NULL default '0',
179 tag char(3) NOT NULL default '',
180 tagorder tinyint(4) NOT NULL default '1',
181 subfieldid char(1) NOT NULL default '',
182 subfieldorder tinyint(4) NOT NULL default '1',
183 word varchar(255) NOT NULL default '',
184 sndx_word varchar(255) NOT NULL default '',
187 KEY tagorder (tagorder),
188 KEY subfieldid (subfieldid),
189 KEY subfieldorder (subfieldorder),
191 KEY sndx_word (sndx_word)
193 marc_breeding => "( id bigint(20) NOT NULL auto_increment,
194 file varchar(80) NOT NULL default '',
195 isbn varchar(10) NOT NULL default '',
196 title varchar(128) default NULL,
197 author varchar(80) default NULL,
199 encoding varchar(40) default NULL,
204 authorised_values => "(id int(11) NOT NULL auto_increment,
205 category char(10) NOT NULL default '',
206 authorised_value char(80) NOT NULL default '',
211 userflags => "( bit int(11) NOT NULL default '0',
212 flag char(30), flagdesc char(255),
216 authtypecode char(10) not NULL,
217 authtypetext char(255) not NULL,
218 auth_tag_to_report char(3) not NULL,
219 summary text not NULL,
220 PRIMARY KEY (authtypecode)
222 biblio_framework => "(
223 frameworkcode char(4) not NULL,
224 frameworktext char(255) not NULL,
225 PRIMARY KEY (frameworkcode)
227 auth_subfield_structure => "(
228 authtypecode char(10) NOT NULL default '',
229 tagfield char(3) NOT NULL default '',
230 tagsubfield char(1) NOT NULL default '',
231 liblibrarian char(255) NOT NULL default '',
232 libopac char(255) NOT NULL default '',
233 repeatable tinyint(4) NOT NULL default '0',
234 mandatory tinyint(4) NOT NULL default '0',
235 tab tinyint(1) default NULL,
236 authorised_value char(10) default NULL,
237 value_builder char(80) default NULL,
238 seealso char(255) default NULL,
239 PRIMARY KEY (authtypecode,tagfield,tagsubfield),
240 KEY tab (authtypecode,tab)
242 auth_tag_structure => "(
243 authtypecode char(10) NOT NULL default '',
244 tagfield char(3) NOT NULL default '',
245 liblibrarian char(255) NOT NULL default '',
246 libopac char(255) NOT NULL default '',
247 repeatable tinyint(4) NOT NULL default '0',
248 mandatory tinyint(4) NOT NULL default '0',
249 authorised_value char(10) default NULL,
250 PRIMARY KEY (authtypecode,tagfield)
253 authid bigint(20) unsigned NOT NULL auto_increment,
254 authtypecode char(10) NOT NULL default '',
255 datecreated date NOT NULL default '0000-00-00',
256 datemodified date default NULL,
257 origincode char(20) default NULL,
258 PRIMARY KEY (authid),
259 KEY origincode (origincode)
261 auth_subfield_table => "(
262 subfieldid bigint(20) unsigned NOT NULL auto_increment,
263 authid bigint(20) unsigned NOT NULL default '0',
264 tag char(3) NOT NULL default '',
265 tagorder tinyint(4) NOT NULL default '1',
266 tag_indicator char(2) NOT NULL default '',
267 subfieldcode char(1) NOT NULL default '',
268 subfieldorder tinyint(4) NOT NULL default '1',
269 subfieldvalue varchar(255) default NULL,
270 PRIMARY KEY (subfieldid),
273 KEY subfieldcode (subfieldcode),
274 KEY subfieldvalue (subfieldvalue)
277 authid bigint(20) NOT NULL default '0',
278 tagsubfield char(4) NOT NULL default '',
279 tagorder tinyint(4) NOT NULL default '1',
280 subfieldorder tinyint(4) NOT NULL default '1',
281 word varchar(255) NOT NULL default '',
282 sndx_word varchar(255) NOT NULL default '',
284 KEY marc_search (tagsubfield,word),
286 KEY sndx_word (sndx_word)
289 suggestionid int(8) NOT NULL auto_increment,
290 suggestedby int(11) NOT NULL default '0',
291 managedby int(11) default NULL ,
292 STATUS varchar(10) NOT NULL default '',
294 author varchar(80) default NULL ,
295 title varchar(80) default NULL ,
296 copyrightdate smallint(6) default NULL ,
297 publishercode varchar(255) default NULL ,
298 date timestamp(8) NOT NULL ,
299 volumedesc varchar(255) default NULL ,
300 publicationyear smallint(6) default '0',
301 place varchar(255) default NULL ,
302 isbn varchar(10) default NULL ,
303 mailoverseeing smallint(1) default '0',
304 biblionumber int(11) default NULL ,
305 PRIMARY KEY (suggestionid) ,
306 KEY suggestedby(suggestedby) ,
307 KEY managedby(managedby)
309 aqbasket => "(basketno int(11) NOT NULL auto_increment,
312 booksellerid varchar(10),
313 authorisedby varchar(10),
314 booksellerinvoicenumber text,
315 PRIMARY KEY (basketno)
317 serial => "(serialid int(11) NOT NULL auto_increment,
318 biblionumber varchar(100) NOT NULL default '',
319 subscriptionid varchar(100) NOT NULL default '',
320 serialseq varchar(100) NOT NULL default '',
321 status tinyint(4) NOT NULL default '0',
322 planneddate date NOT NULL default '0000-00-00',
323 PRIMARY KEY (serialid)
325 subscription => "(biblionumber int(11) NOT NULL default '0',
326 subscriptionid int(11) NOT NULL auto_increment,
327 librarian varchar(100) default '',
328 startdate date default '0000-00-00',
329 aqbooksellerid int(11) default '0',
330 cost int(11) default '0',
331 aqbudgetid int(11) default '0',
332 weeklength tinyint(4) default '0',
333 monthlength tinyint(4) default '0',
334 numberlength tinyint(4) default '0',
335 periodicity tinyint(4) default '0',
336 dow varchar(100) default '',
337 numberingmethod varchar(100) default '',
339 status varchar(100) NOT NULL default '',
340 add1 int(11) default 0,
341 every1 int(11) default 0,
342 whenmorethan1 int(11) default 0,
345 add2 int(11) default 0,
346 every2 int(11) default 0,
347 whenmorethan2 int(11) default 0,
350 add3 int(11) default 0,
351 every3 int(11) default 0,
352 innerloop1 int(11) default 0,
353 innerloop2 int(11) default 0,
354 innerloop3 int(11) default 0,
355 whenmorethan3 int(11) default 0,
358 PRIMARY KEY (subscriptionid)
360 subscriptionhistory => "(biblionumber int(11) NOT NULL default '0',
361 subscriptionid int(11) NOT NULL default '0',
362 histstartdate date NOT NULL default '0000-00-00',
363 enddate date default '0000-00-00',
364 missinglist longtext NOT NULL,
365 recievedlist longtext NOT NULL,
366 opacnote varchar(150) NOT NULL default '',
367 librariannote varchar(150) NOT NULL default '',
368 PRIMARY KEY (subscriptionid),
369 KEY biblionumber (biblionumber)
371 categorytable => "(categorycode char(5) NOT NULL default '',
372 description text default '',
373 itemtypecodes text default '',
374 PRIMARY KEY (categorycode)
376 subcategorytable => "(subcategorycode char(5) NOT NULL default '',
377 description text default '',
378 itemtypecodes text default '',
379 PRIMARY KEY (subcategorycode)
381 mediatypetable => "(mediatypecode char(5) NOT NULL default '',
382 description text default '',
383 itemtypecodes text default '',
384 PRIMARY KEY (mediatypecode)
387 `timestamp` TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL ,
388 `user` INT( 11 ) NOT NULL ,
389 `module` TEXT default '',
390 `action` TEXT default '' ,
391 `object` INT(11) default '' ,
392 `info` TEXT default '' ,
393 PRIMARY KEY ( `timestamp` , `user` )
397 my %requirefields = (
398 biblio => { 'abstract' => 'text' },
399 deletedbiblio => { 'abstract' => 'text', 'marc' => 'blob' },
400 deleteditems => { 'marc' => 'blob', 'paidfor' => 'text', 'location' => 'varchar(80)'},
402 'lccn' => 'char(25)',
403 'url' => 'varchar(255)',
406 deletedbiblioitems => {
407 'lccn' => 'char(25)',
408 'url' => 'varchar(255)',
411 branchtransfers => { 'datearrived' => 'datetime' },
412 statistics => { 'borrowernumber' => 'int(11)' },
414 'invoicedisc' => 'float(6,4)',
415 'nocalc' => 'int(11)'
418 'userid' => 'char(30)',
419 'password' => 'char(30)',
420 'flags' => 'int(11)',
421 'textmessaging' => 'varchar(30)',
422 'zipcode' => 'varchar(25)',
423 'homezipcode' => 'varchar(25)',
424 'sort1' => 'char(80)',
425 'sort2' => 'char(80)',
427 aqorders => { 'budgetdate' => 'date',
428 'sort1' => 'char(80)',
429 'sort2' => 'char(80)', },
430 aqbookfund =>{'branchcode'=> 'varchar(4) NULL'},
431 aqbudget => {'aqbudgetid' => 'tinyint(4) auto_increment primary key', 'branchcode'=> 'varchar(4) NULL'},
432 items => {'paidfor' => 'text', 'location' => 'char(80)'},
434 #added so that reference items are not available for reserves...
435 itemtypes => { 'notforloan' => 'smallint(6)' },
436 systempreferences => { 'explanation' => 'char(80)',
437 'type' => 'char(20)',
438 'options' => 'text' },
439 z3950servers => { 'syntax' => 'char(80)' },
440 marc_tag_structure =>{
441 'frameworkcode' => 'char(4) not NULL default \'\''},
442 marc_subfield_structure =>{'seealso' => 'char(255)',
443 'frameworkcode' => 'char(4) not NULL default \'\'',
444 'hidden' => 'tinyint(1)',
445 'isurl' => 'tinyint(1)',
446 'link' => 'char(80)',
448 bookshelf => {'owner' => 'char(80)',
449 'category' => 'char(1)',
451 marc_biblio => { 'frameworkcode' => 'char(4) not NULL default \'\'' },
454 my %dropable_table = (
455 classification => 'classification',
456 multipart => 'multipart',
457 multivolume => 'multivolume',
458 newitems => 'newitems',
459 procedures => 'procedures',
460 publisher => 'publisher',
461 searchstats => 'searchstats',
462 serialissues => 'serialissues',
465 my %uselessfields = (
466 aqorders => "requisitionedby,authorisedby,booksellerid,
467 deliverydays,followupdays,
468 numberfollowupsallowed,numberfollowupssent,
469 dateprinted,sourced,quantityreceiveddamaged,
470 subscriptionfrom,subscriptionto
473 # the other hash contains other actions that can't be done elsewhere. they are done
474 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
476 # The tabledata hash contains data that should be in the tables.
477 # The uniquefieldrequired hash entry is used to determine which (if any) fields
478 # must not exist in the table for this row to be inserted. If the
479 # uniquefieldrequired entry is already in the table, the existing data is not
480 # modified, unless the forceupdate hash entry is also set. Fields in the
481 # anonymous "forceupdate" hash will be forced to be updated to the default
482 # values given in the %tabledata hash.
487 uniquefieldrequired => 'bit',
489 flag => 'superlibrarian',
490 flagdesc => 'Access to all librarian functions',
494 uniquefieldrequired => 'bit',
497 flagdesc => 'Circulate books',
501 uniquefieldrequired => 'bit',
504 flagdesc => 'View Catalogue (Librarian Interface)',
508 uniquefieldrequired => 'bit',
510 flag => 'parameters',
511 flagdesc => 'Set Koha system paramters',
515 uniquefieldrequired => 'bit',
518 flagdesc => 'Add or modify borrowers',
522 uniquefieldrequired => 'bit',
524 flag => 'permissions',
525 flagdesc => 'Set user permissions',
529 uniquefieldrequired => 'bit',
531 flag => 'reserveforothers',
532 flagdesc => 'Reserve books for patrons',
536 uniquefieldrequired => 'bit',
539 flagdesc => 'Borrow books',
543 uniquefieldrequired => 'bit',
545 flag => 'reserveforself',
546 flagdesc => 'Reserve books for self',
550 uniquefieldrequired => 'bit',
552 flag => 'editcatalogue',
553 flagdesc => 'Edit Catalogue (Modify bibliographic/holdings data)',
557 uniquefieldrequired => 'bit',
559 flag => 'updatecharges',
560 flagdesc => 'Update borrower charges',
564 uniquefieldrequired => 'bit',
566 flag => 'acquisition',
567 flagdesc => 'Acquisition and/or suggestion management',
571 uniquefieldrequired => 'bit',
573 flag => 'management',
574 flagdesc => 'Set library management parameters',
578 uniquefieldrequired => 'bit',
581 flagdesc => 'Use tools (export, import, barcodes)',
585 systempreferences => [
587 uniquefieldrequired => 'variable',
588 forceupdate => { 'explanation' => 1,
590 variable => 'LibraryName',
591 value => '<i><b>Koha<br/>Free Software ILS<br/><br/></b>Koha : a gift, a contribution<br/> in Maori</i>',
592 explanation => 'Library name as shown on main opac page',
597 uniquefieldrequired => 'variable',
598 forceupdate => { 'explanation' => 1,
600 variable => 'autoMemberNum',
602 explanation => 'Member number is auto-calculated',
607 uniquefieldrequired => 'variable',
608 forceupdate => { 'explanation' => 1,
611 variable => 'acquisitions',
614 'Normal, budget-based acquisitions, or Simple bibliographic-data acquisitions',
616 options => 'simple|normal'
619 uniquefieldrequired => 'variable',
620 forceupdate => { 'explanation' => 1,
623 variable => 'dateformat',
626 'date format (us mm/dd/yyyy, metric dd/mm/yyy, ISO yyyy/mm/dd)',
628 options => 'metric|us|iso'
631 uniquefieldrequired => 'variable',
632 variable => 'template',
633 forceupdate => { 'explanation' => 1,
636 explanation => 'Preference order for intranet interface templates',
640 uniquefieldrequired => 'variable',
641 variable => 'autoBarcode',
642 forceupdate => { 'explanation' => 1,
645 explanation => 'Barcode is auto-calculated',
649 uniquefieldrequired => 'variable',
650 variable => 'insecure',
651 forceupdate => { 'explanation' => 1,
655 'If YES, no auth at all is needed. Be careful if you set this to yes!',
659 uniquefieldrequired => 'variable',
660 variable => 'authoritysep',
661 forceupdate => { 'explanation' => 1,
666 'the separator used in authority/thesaurus. Usually --',
671 uniquefieldrequired => 'variable',
672 variable => 'opaclanguages',
673 forceupdate => { 'explanation' => 1,
676 explanation => 'Set the preferred order for translations. The top language will be tried first.',
680 uniquefieldrequired => 'variable',
681 variable => 'opacthemes',
682 forceupdate => { 'explanation' => 1,
685 explanation => 'Set the preferred order for themes. The top theme will be tried first.',
689 uniquefieldrequired => 'variable',
690 variable => 'timeout',
691 forceupdate => { 'explanation' => 1,
694 explanation => 'Inactivity timeout for cookies authentication (in seconds)',
698 uniquefieldrequired => 'variable',
700 forceupdate => { 'explanation' => 1,
703 explanation => 'Turn on MARC support',
707 uniquefieldrequired => 'variable',
708 variable => 'marcflavour',
709 forceupdate => { 'explanation' => 1,
714 'your MARC flavor (MARC21 or UNIMARC) used for character encoding',
716 options => 'MARC21|UNIMARC'
719 uniquefieldrequired => 'variable',
720 variable => 'checkdigit',
722 forceupdate => { 'explanation' => 1,
725 explanation => 'Validity checks on membership number: none or "Katipo" style checks',
727 options => 'none|katipo'
730 uniquefieldrequired => 'variable',
731 variable => 'maxoutstanding',
732 forceupdate => { 'explanation' => 1,
736 'maximum amount withstanding to be able make reserves ',
740 uniquefieldrequired => 'variable',
741 variable => 'maxreserves',
742 forceupdate => { 'explanation' => 1,
746 'maximum number of reserves a member can make',
751 uniquefieldrequired => 'variable',
752 variable => 'noissuescharge',
753 forceupdate => { 'explanation' => 1,
757 'maximum amount withstanding to be able to check out an item',
762 uniquefieldrequired => 'variable',
763 variable => 'KohaAdminEmailAddress',
764 forceupdate => { 'explanation' => 1,
766 value => 'your.mail@here',
767 explanation => 'the email address where borrowers modifs are sent',
771 uniquefieldrequired => 'variable',
773 forceupdate => { 'explanation' => 1,
776 explanation => 'the gist rate. NOT in %, but in numeric form (0.12 for 12%)',
780 uniquefieldrequired => 'variable',
781 variable => 'printcirculationslips',
782 forceupdate => { 'explanation' => 1,
785 explanation => 'if set to 1, print circulation slips. If set to 0, don\'t',
789 uniquefieldrequired => 'variable',
790 variable => 'suggestion',
791 forceupdate => { 'explanation' => 1,
794 explanation => 'if set to 1, suggestions are activated in OPAC',
798 uniquefieldrequired => 'variable',
800 forceupdate => { 'explanation' => 1,
802 value => 'Fill with appropriate value...',
803 explanation => 'ISBD',
807 uniquefieldrequired => 'variable',
808 variable => 'virtualshelves',
809 forceupdate => { 'explanation' => 1,
812 explanation => 'Set virtual shelves management ON or OFF',
816 uniquefieldrequired => 'variable',
817 variable => 'itemcallnumber',
818 forceupdate => { 'explanation' => 1,
821 explanation => 'The MARC field/subfield that is used to calculate the itemcallnumber (in UNIMARC : 676a for Dewey, 680a for Loc)',
825 uniquefieldrequired => 'variable',
826 variable => 'BiblioDefaultView',
828 forceupdate => { 'explanation' => 1,
831 explanation => 'Define the default view of a biblio. Can be either normal, marc or isbd',
833 options => 'normal|marc|isbd'
836 uniquefieldrequired => 'variable',
837 variable => 'opacstylesheet',
839 forceupdate => { 'explanation' => 1,
841 explanation => 'Enter a complete URL to use an alternate stylesheet in OPAC',
845 uniquefieldrequired => 'variable',
846 variable => 'opacsmallimage',
848 forceupdate => { 'explanation' => 1,
850 explanation => 'Enter a complete URL to an image, will be on top/left instead of the Koha logo',
854 uniquefieldrequired => 'variable',
855 variable => 'opaclargeimage',
857 forceupdate => { 'explanation' => 1,
859 explanation => 'Enter a complete URL to an image, will be on the main page, instead of the Koha logo',
863 uniquefieldrequired => 'variable',
864 variable => 'delimiter',
866 forceupdate => { 'explanation' => 1,
868 explanation => 'separator for reports exported to spreadsheet',
872 uniquefieldrequired => 'variable',
874 value => 'OPENOFFICE.ORG',
875 forceupdate => { 'explanation' => 1,
878 explanation => 'Define the default application for report exportations into files',
880 options => 'EXCEL|OPENOFFICE.ORG'
883 uniquefieldrequired => 'variable',
884 variable => 'Delimiter',
886 forceupdate => { 'explanation' => 1,
889 explanation => 'Define the default separator character for report exportations into files',
891 options => ';|tabulation|,|/|\|#'
894 uniquefieldrequired => 'variable',
895 variable => 'SubscriptionHistory',
897 forceupdate => { 'explanation' => 1,
900 explanation => 'Define the information level for serials history in OPAC',
902 options => 'simplified|full'
905 uniquefieldrequired => 'variable',
906 variable => 'hidelostitems',
908 forceupdate => { 'explanation' => 1,
910 explanation => 'show or hide "lost" items in OPAC.',
914 uniquefieldrequired => 'variable',
915 variable => 'Activate_Log',
917 forceupdate => { 'explanation' => 1,
919 explanation => 'Turn Log Actions on DB On an Off',
926 my %fielddefinitions = (
929 field => 'printername',
938 field => 'bookfundid',
945 field => 'branchcode',
946 type => 'varchar(4)',
955 field => 'aqbudgetid',
956 type => 'tinyint(4)',
960 extra => 'auto_increment'
963 field => 'branchcode',
964 type => 'varchar(4)',
978 extra => 'auto_increment'
983 field => 'z3950random',
984 type => 'varchar(40)',
992 type => 'varchar(40)',
1001 #-------------------
1006 # Get version of MySQL database engine.
1007 my $mysqlversion = `mysqld --version`;
1008 $mysqlversion =~ /Ver (\S*) /;
1010 if ( $mysqlversion ge '3.23' ) {
1011 print "Could convert to MyISAM database tables...\n" unless $silent;
1014 #---------------------------------
1017 # Collect all tables into a list
1018 $sth = $dbh->prepare("show tables");
1020 while ( my ($table) = $sth->fetchrow ) {
1021 $existingtables{$table} = 1;
1025 # Now add any missing tables
1026 foreach $table ( keys %requiretables ) {
1027 unless ( $existingtables{$table} ) {
1028 print "Adding $table table...\n" unless $silent;
1029 my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1032 print "Error : $sth->errstr \n";
1038 # now drop useless tables
1039 foreach $table ( keys %dropable_table ) {
1040 if ( $existingtables{$table} ) {
1041 print "Dropping unused table $table\n" if $debug and not $silent;
1042 $dbh->do("drop table $table");
1044 print "Error : $dbh->errstr \n";
1048 unless ( $existingtables{'z3950servers'} ) {
1049 #MJR: added syntax entries to close bug 624
1050 print "Adding z3950servers table...\n" unless $silent;
1051 my $sti = $dbh->prepare( "create table z3950servers (
1064 $sti = $dbh->prepare( "insert into z3950servers
1065 values ('z3950.loc.gov',
1069 'Library of Congress',
1074 unless ( $existingtables{'issuingrules'} ) {
1075 $dbh->do("alter table categoryitem rename issuingrules");
1076 $dbh->do("ALTER TABLE issuingrules ADD maxissueqty int(4) default NULL");
1077 $dbh->do("ALTER TABLE issuingrules ADD issuelength int(4) default NULL");
1078 $dbh->do("ALTER TABLE issuingrules ADD branchcode varchar(4) NOT NULL default ''");
1079 print "renaming categoryitem\n" unless $silent;
1083 #---------------------------------
1086 foreach $table ( keys %requirefields ) {
1087 print "Check table $table\n" if $debug and not $silent;
1088 $sth = $dbh->prepare("show columns from $table");
1091 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1093 $types{$column} = $type;
1095 foreach $column ( keys %{ $requirefields{$table} } ) {
1096 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
1097 if ( !$types{$column} ) {
1099 # column doesn't exist
1100 print "Adding $column field to $table table...\n" unless $silent;
1101 $query = "alter table $table
1102 add column $column " . $requirefields{$table}->{$column};
1103 print "Execute: $query\n" if $debug;
1104 my $sti = $dbh->prepare($query);
1107 print "**Error : $sti->errstr \n";
1114 foreach $table ( keys %fielddefinitions ) {
1115 print "Check table $table\n" if $debug;
1116 $sth = $dbh->prepare("show columns from $table");
1119 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1121 $definitions->{$column}->{type} = $type;
1122 $definitions->{$column}->{null} = $null;
1123 $definitions->{$column}->{key} = $key;
1124 $definitions->{$column}->{default} = $default;
1125 $definitions->{$column}->{extra} = $extra;
1127 my $fieldrow = $fielddefinitions{$table};
1128 foreach my $row (@$fieldrow) {
1129 my $field = $row->{field};
1130 my $type = $row->{type};
1131 my $null = $row->{null};
1132 my $key = $row->{key};
1133 my $default = $row->{default};
1134 $default="''" unless $default;
1135 my $extra = $row->{extra};
1136 my $def = $definitions->{$field};
1137 unless ( $type eq $def->{type}
1138 && $null eq $def->{null}
1139 && $key eq $def->{key}
1140 && $default eq $def->{default}
1141 && $extra eq $def->{extra} )
1144 if ( $null eq '' ) {
1147 if ( $key eq 'PRI' ) {
1148 $key = 'PRIMARY KEY';
1150 unless ( $extra eq 'auto_increment' ) {
1153 # if it's a new column use "add", if it's an old one, use "change".
1155 if ($definitions->{$field}->{type}) {
1156 $action="change $field"
1160 # if it's a primary key, drop the previous pk, before altering the table
1162 if ($key ne 'PRIMARY KEY') {
1163 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
1165 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
1167 $sth->execute($default);
1168 print " Alter $field in $table\n" unless $silent;
1173 # Get list of columns from borrowers table
1176 $sth = $dbh->prepare("show columns from borrowers");
1178 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1180 $itemtypes{$column} = $type;
1181 $nullenabled{$column} = $null;
1184 unless ( $itemtypes{'cardnumber'} eq 'varchar(20)' ) {
1185 $itemtypes{'cardnumber'} =~ /varchar\((\d+)\)/;
1187 if ( $oldlength < 16 ) {
1188 print "Setting maximum cardnumber length to 16 (was $oldlength) and marking unique.\n" unless $silent;
1191 "alter table borrowers change cardnumber cardnumber varchar(16)");
1196 "alter table borrowers drop index cardnumber");
1201 "alter table borrowers add unique(cardnumber)");
1207 # Get list of columns from items table
1208 $sth = $dbh->prepare("show columns from items");
1210 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1212 $itemtypes{$column} = $type;
1213 $nullenabled{$column} = $null;
1216 unless ( $itemtypes{'barcode'} eq 'varchar(20)' ) {
1217 $itemtypes{'barcode'} =~ /varchar\((\d+)\)/;
1219 if ( $oldlength < 20 ) {
1220 print "Setting maximum barcode length to 20 (was $oldlength).\n" unless $silent;
1223 "alter table items change barcode barcode varchar(20)");
1228 # dropping unique barcode index & setting barcode to null allowed.
1230 $sth = $dbh->prepare("show index from items");
1232 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1234 if ($key_name eq 'barcode' && $non_unique eq 0) {
1235 print "dropping BARCODE index to enable empty barcodes\n" unless $silent;
1236 $dbh->do("ALTER TABLE `items` DROP INDEX `barcode`");
1239 $dbh->do("ALTER TABLE `items` CHANGE `barcode` `barcode` VARCHAR( 20 )") unless ($nullenabled{barcode} eq 'YES');
1242 # creating fulltext index in bibliothesaurus if needed
1244 $sth = $dbh->prepare("show index from bibliothesaurus");
1247 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1249 if ($key_name eq 'category_2') {
1253 print "Creating fulltext index on bibliothesaurus\n" unless $exists or $silent;
1254 $dbh->do('create fulltext index category_2 on bibliothesaurus (category,freelib)') unless $exists;
1257 # creating index in z3950results if needed
1259 $sth = $dbh->prepare("show index from z3950results");
1262 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1264 if ($key_name eq 'query_server') {
1268 print "Creating index on z3950results\n" unless $exists or $silent;
1269 $dbh->do('create unique index query_server on z3950results (queryid,server)') unless $exists;
1271 # changing z3950daemon field to NULL in marc_breeding
1272 $dbh->do("ALTER TABLE `marc_breeding` CHANGE `z3950random` `z3950random` VARCHAR( 40 )");
1274 # making borrowernumber an auto_increment field
1275 $dbh->do("ALTER TABLE `borrowers` CHANGE `borrowernumber` `borrowernumber` INTEGER auto_increment");
1277 # changing indexes in marc_*_structure to use frameworkcode
1278 $dbh->do('alter table marc_subfield_structure drop index tab');
1279 $dbh->do('create index tab on marc_subfield_structure (frameworkcode,tab)');
1280 $dbh->do('alter table marc_subfield_structure drop index kohafield');
1281 $dbh->do('create index kohafield on marc_subfield_structure (frameworkcode,kohafield)');
1284 # extending the timestamp in branchtransfers...
1285 my %branchtransfers;
1287 $sth = $dbh->prepare("show columns from branchtransfers");
1289 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1291 $branchtransfers{$column} = $type;
1294 unless ( $branchtransfers{'datesent'} eq 'datetime' ) {
1295 print "Setting type of datesent in branchtransfers to datetime.\n" unless $silent;
1298 "alter table branchtransfers change datesent datesent datetime");
1302 unless ( $branchtransfers{'datearrived'} eq 'datetime' ) {
1303 print "Setting type of datearrived in branchtransfers to datetime.\n" unless $silent;
1306 "alter table branchtransfers change datearrived datearrived datetime");
1310 # changing the branchcategories table around...
1311 my %branchcategories;
1313 $sth = $dbh->prepare("show columns from branchcategories");
1315 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1317 $branchcategories{$column} = $type;
1320 unless ( $branchcategories{'categorycode'} eq 'varchar(4)' ) {
1322 "Setting type of categorycode in branchcategories to varchar(4),\n and making the primary key.\n" unless $silent;
1325 "alter table branchcategories change categorycode categorycode varchar(4) not null"
1330 "alter table branchcategories add primary key (categorycode)");
1334 unless ( $branchcategories{'categoryname'} eq 'text' ) {
1335 print "Changing branchcode in branchcategories to categoryname text.\n" unless $silent;
1338 "alter table branchcategories change branchcode categoryname text");
1342 unless ( $branchcategories{'codedescription'} eq 'text' ) {
1344 "Replacing branchholding in branchcategories with codedescription text.\n" unless $silent;
1347 "alter table branchcategories change branchholding codedescription text"
1352 # changing the items table around...
1355 $sth = $dbh->prepare("show columns from items");
1357 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1359 $items{$column} = $type;
1362 if ($items{'bulk'} eq "varchar(30)") {
1363 print " Setting callnumber in items table\n" unless $silent;
1365 $dbh->prepare("ALTER TABLE `items` CHANGE `bulk` `itemcallnumber` VARCHAR( 30 ) DEFAULT NULL");
1367 $sti = $dbh->prepare("update marc_subfield_structure set kohafield=\"items.itemcallnumber\" where kohafield=\"items.bulk\"");
1371 # changing the marc_subfield_structure table around...
1372 my %marc_subfield_structure;
1374 $sth = $dbh->prepare("show columns from marc_subfield_structure");
1376 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1378 $marc_subfield_structure{$column} = $type;
1381 if ($marc_subfield_structure{thesaurus_category}) {
1382 print " changing thesaurus_category in marc_subfield_structure table\n" unless $silent;
1384 $dbh->prepare("ALTER TABLE marc_subfield_structure CHANGE `thesaurus_category` `authtypecode` VARCHAR(10 ) DEFAULT NULL");
1389 # creating index in issuingrules if needed
1391 $sth = $dbh->prepare("show index from issuingrules");
1394 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow )
1396 if ($key_name eq 'PRIMARY') {
1400 print "Creating index on issuing rules\n" unless $exists or $silent;
1401 $dbh->do('ALTER TABLE issuingrules ADD PRIMARY KEY ( branchcode, categorycode, itemtype )') unless $exists;
1403 $dbh->do('ALTER TABLE marc_tag_structure drop primary key');
1404 $dbh->do('ALTER TABLE marc_tag_structure ADD PRIMARY KEY ( frameworkcode, tagfield )');
1406 $dbh->do('ALTER TABLE marc_subfield_structure drop primary key');
1407 $dbh->do('ALTER TABLE marc_subfield_structure ADD PRIMARY KEY ( frameworkcode, tagfield, tagsubfield )');
1409 # Get list of columns from marc_word table
1412 $sth = $dbh->prepare("show columns from marc_word");
1414 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1416 $marc_word{$column} = $type;
1417 $nullenabled{$column} = $null;
1419 if ($marc_word{subfieldid}) {
1420 #create field tagsubfield, copy tag+subfieldid, then drop tag and subfieldid
1421 print "Modifying marc_word (concat on tag and subfield for better perfs)\n" unless $silent;
1422 $dbh->do("ALTER TABLE `marc_word` ADD `tagsubfield` CHAR( 4 ) NOT NULL AFTER `bibid`");
1423 $dbh->do("update marc_word set tagsubfield=concat(tag,subfieldid)");
1424 $dbh->do("alter table marc_word drop tag");
1425 $dbh->do("alter table marc_word drop subfieldid");
1426 $dbh->do("create index Search_Marc on marc_word (tagsubfield,word)");
1428 # Populate tables with required data
1430 # fill aqbasket if it's empty and aqorder is not
1431 # => it means it has just been created & must be filled
1432 $sth = $dbh->prepare("select count(*) from aqbasket");
1434 if ($sth->fetchrow == 0) {
1435 $sth = $dbh->prepare("select count(*) from aqorders");
1437 if ($sth->fetchrow >0) {
1438 print "Populating new table aqbasket\n";
1439 print "IMPORTANT NOTE: error message \"Duplicate entry 'X' for key 1\" may appear. it should not be a real trouble\n";
1440 $sth=$dbh->prepare("select distinct basketno,booksellerid,authorisedby,entrydate,booksellerinvoicenumber from aqorders");
1442 my ($basketno,$booksellerid,$authorisedby,$entrydate,$booksellerinvoicenumber);
1443 my $sth2 = $dbh->prepare("insert into aqbasket (basketno,creationdate,booksellerid,authorisedby,booksellerinvoicenumber) values (?,?,?,?,?)");
1444 while (($basketno,$booksellerid,$authorisedby,$entrydate,$booksellerinvoicenumber) = $sth->fetchrow) {
1445 print "$basketno,$entrydate,$booksellerid,$authorisedby,$booksellerinvoicenumber\n";
1446 $sth2->execute($basketno,$entrydate,$booksellerid,$authorisedby,$booksellerinvoicenumber);
1450 foreach my $table ( keys %tabledata ) {
1451 print "Checking for data required in table $table...\n" unless $silent;
1452 my $tablerows = $tabledata{$table};
1453 foreach my $row (@$tablerows) {
1454 my $uniquefieldrequired = $row->{uniquefieldrequired};
1455 my $uniquevalue = $row->{$uniquefieldrequired};
1456 my $forceupdate = $row->{forceupdate};
1459 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1461 $sth->execute($uniquevalue);
1463 foreach my $field (keys %$forceupdate) {
1464 if ($forceupdate->{$field}) {
1465 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1466 $sth->execute($row->{$field}, $uniquevalue);
1470 print "Adding row to $table: " unless $silent;
1474 foreach my $field ( keys %$row ) {
1475 next if $field eq 'uniquefieldrequired';
1476 next if $field eq 'forceupdate';
1477 my $value = $row->{$field};
1478 push @values, $value;
1479 print " $field => $value" unless $silent;
1480 $fieldlist .= "$field,";
1481 $placeholders .= "?,";
1483 print "\n" unless $silent;
1484 $fieldlist =~ s/,$//;
1485 $placeholders =~ s/,$//;
1488 "insert into $table ($fieldlist) values ($placeholders)");
1489 $sth->execute(@values);
1494 # at last, remove useless fields
1495 foreach $table ( keys %uselessfields ) {
1496 my @fields = split /,/,$uselessfields{$table};
1499 foreach my $fieldtodrop (@fields) {
1500 $fieldtodrop =~ s/\t//g;
1501 $fieldtodrop =~ s/\n//g;
1503 $sth = $dbh->prepare("show columns from $table");
1505 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1507 $exists =1 if ($column eq $fieldtodrop);
1510 print "deleting $fieldtodrop field in $table...\n" unless $silent;
1511 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
1523 # Revision 1.109 2005/07/19 16:48:16 hdl
1524 # Adding an object field to action_logs.
1525 # + Minor Correction to updatedatabase
1526 # Changing Activate_Log from choice to YesNo Variable.
1528 # Revision 1.108 2005/07/15 16:10:35 hdl
1529 # Adding Log Facility.
1530 # Needs Two Update in database...
1531 # On more table (action_logs)
1532 # And One more syspref Activate_Log, with On|Off values.
1533 # Maintainance has been sweeped of previous Log functions
1534 # addbiblio.pl contains a sample of code using Log.pm
1535 # To be generalized to Authorities, acquisitions, members soon.
1537 # Revision 1.107 2005/07/14 09:53:10 hdl
1538 # Adding a log facility for actions watching.
1539 # Code to be widely used in order to report data modifications.
1541 # Revision 1.106 2005/07/06 17:47:22 hdl
1542 # Add branch selection and filter for budgets and funds.
1543 # May be too much... Funds could be enough....
1545 # It works provided you update your base adding branchcode both in aqbookfund AND aqbudget.
1546 # If selection in budget is not needed, I shall remove.
1548 # Revision 1.105 2005/06/20 14:36:44 tipaul
1549 # synch'ing 2.2 and head
1551 # Revision 1.100.2.5 2005/06/06 15:23:36 tipaul
1552 # adding a systempref to choose either to show or hide "lost" items. Note that "lost items" can be related to an authorised value list, so does not necessary mean "item definetly lost". Even here, some libraries want to see lost items, and some don't want. This parameter will make everybody happy !
1554 # Revision 1.100.2.4 2005/06/06 14:15:55 tipaul
1555 # adding 2 systemparameters to define an alternate image as logo in opac (the image on main page & on each top-left page)
1557 # Revision 1.100.2.3 2005/06/02 21:05:34 hdl
1558 # adding variable SubscriptionHistory
1560 # Revision 1.100.2.2 2005/03/29 15:41:43 tipaul
1561 # * new permissions : management & tools. You now have 2 new permissions :
1562 # - management : means the user can manage library parameters, but NOT system parameters.
1563 # - parameters : means the user can manage all parameters (including system parameters : marc structure, authorised values, system preferences. Was the only flag previously existing)
1564 # - tools : means the user can import/export datas & edit barcodes.
1565 # note that for compatibility reasons, a user having "parameters" can access everything.
1566 # * new permission scheme. In every template new variables are available. They are written CAN_user_permission, with permission being one of the permission flag. templates can now show or hidde menu entries depending on user permissions. For example, a user with just circ permissions should have only the "circulation" button on home page. Templates are NOT updated in this version (except for system parameters, as proof of concept), they will be in the next ones. But the scheme is ready.
1568 # Revision 1.100.2.1 2005/03/17 17:15:18 tipaul
1569 # defaulting opacstylesheet to '' instead of 'normal' (that is stupid)
1571 # Revision 1.100 2004/12/10 16:11:32 tipaul
1572 # Improvement : adding a systempref to define default view in OPAC (either normal, MARC or ISBD). Created automatically during install or update. Check that you have a Koha >> parameters >> systempreferences >> BiblioDefaultView, Variable type : Choice, Variable options : normal|marc|isbd
1574 # Revision 1.99 2004/12/02 17:17:00 tipaul
1575 # adding acquisition permission
1577 # Revision 1.98 2004/11/26 20:26:49 tipaul
1578 # bugfix for auth_header creation
1580 # Revision 1.97 2004/11/23 09:11:08 tipaul
1581 # adding itemcallnumber entry
1583 # Revision 1.96 2004/11/16 13:03:45 tipaul
1584 # removing ldap systempref, it's now in C4/Auth_with_ldap.pm separate package
1586 # Revision 1.95 2004/11/08 19:57:32 tipaul
1589 # Revision 1.94 2004/09/06 10:00:29 tipaul
1590 # adding a "location" field to the library.
1591 # This field is useful when the callnumber contains no information on the room where the item is stored.
1592 # With this field, we now have 3 levels of informations to find a book :
1597 # This should be versatile enough to solve any storing method.
1598 # This hack is quite simple, due to the nice Biblio.pm API. The MARC => koha db link is automatically managed. Just add the link in the parameters section.
1600 # Revision 1.93 2004/08/12 14:50:50 tipaul
1603 # Revision 1.92 2004/08/06 16:38:42 tipaul
1604 # changing DB structure to calculate next issue number.
1605 # Seems to work fine.
1607 # Still misses the date calculation & the test of end of subscription (maybe for monday ?)
1609 # Revision 1.91 2004/07/15 09:52:28 tipaul
1610 # Acquisition & Suggestion :
1611 # * acquisition rewritte : create a aqbasket table to deal with "bookseller order header".
1612 # * add "close basket" feature : a closed basket can't be modified
1613 # * suggestion feature : manage suggestions in acquisition (after suggestion filled in OPAC)
1615 # Revision 1.90 2004/07/06 08:24:18 tipaul
1616 # adding 2 free fields that can be used for sorting purposes
1618 # Revision 1.89 2004/07/02 15:55:08 tipaul
1619 # Adding 2 new fields, called "sort1" and "sort2"
1620 # They can be used for sorting & statistics reasons by the library.
1622 # Revision 1.88 2004/06/26 23:34:26 rangi
1625 # Revision 1.87 2004/06/23 13:03:09 tipaul
1626 # fixes in DB structure
1628 # Revision 1.86 2004/06/22 11:30:57 tipaul
1629 # adding -s (silent) flag, to have a silent install.
1630 # only updater will be verbose
1632 # Revision 1.85 2004/06/17 15:19:44 tipaul
1633 # missing Marc_Search index on marc_word
1635 # Revision 1.84 2004/06/17 08:25:21 tipaul
1636 # DB modifs : merging tag & subfield in marc_word table
1638 # Revision 1.83 2004/06/10 08:32:02 tipaul
1639 # MARC authority management (continued)
1641 # Revision 1.82 2004/06/03 12:46:58 tipaul
1642 # * frameworks and itemtypes are independant
1644 # WARNING : will work only if applied to a 2.0 base. some modifs have been done since last commit that will NOT be applied if you run updatedatabase again.
1646 # Revision 1.81 2004/05/28 09:56:21 tipaul
1649 # Revision 1.80 2004/05/28 08:32:00 tipaul
1651 # * MARC authority file
1652 # * seealso & hidden in MARC biblio structure.
1654 # Revision 1.79 2004/05/18 09:50:07 tipaul
1655 # *** empty log message ***
1657 # Revision 1.78 2004/05/10 09:29:33 tipaul
1658 # css is now the default theme for OPAC.
1659 # It will be the theme used for improvements and new things in OPAC.
1661 # Revision 1.77 2004/05/06 14:56:51 tipaul
1662 # adding table issuingrules (previously called categoryitem
1664 # Revision 1.76 2004/05/03 09:32:25 tipaul
1665 # adding printcirculationsplit parameter (already existed, but was not in systempref by defaul)
1667 # Revision 1.75 2004/04/14 19:49:00 tipaul
1668 # seealso field set to 255 chars
1670 # Revision 1.74 2004/03/11 16:10:16 tipaul
1671 # *** empty log message ***
1673 # Revision 1.73 2004/03/06 20:26:13 tipaul
1674 # adding seealso feature in MARC searches