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) default '' ,
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)
181 my %requirefields = (
182 subscription => { 'letter' => 'char(20) NULL', 'distributedto' => 'text NULL'},
183 itemtypes => { 'imageurl' => 'char(200) NULL'},
184 aqbookfund => { 'branchcode' => 'varchar(4) NULL'},
185 aqbudget => { 'branchcode' => 'varchar(4) NULL'},
186 auth_header => { 'marc' => 'BLOB NOT NULL', 'linkid' => 'BIGINT(20) NULL'},
187 auth_subfield_structure =>{ 'hidden' => 'TINYINT(3) NOT NULL UNSIGNED ZEROFILL', 'kohafield' => 'VARCHAR(45) NOT NULL', 'linkid' => 'TINYINT(1) NOT NULL UNSIGNED', 'isurl' => 'TINYINT(1) UNSIGNED'},
188 statistics => { 'associatedborrower' => 'integer'},
189 # tablename => { 'field' => 'fieldtype' },
192 my %dropable_table = (
193 sessionqueries => 'sessionqueries',
194 marcrecorddone => 'marcrecorddone',
196 itemsprices => 'itemsprices',
197 biblioanalysis => 'biblioanalysis',
199 # tablename => 'tablename',
202 my %uselessfields = (
203 # tablename => "field1,field2",
204 borrowers => "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
205 deletedborrowers=> "suburb,altstreetaddress,altsuburb,altcity,studentnumber,school,area,preferredcont,altcp",
207 # the other hash contains other actions that can't be done elsewhere. they are done
208 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
210 # The tabledata hash contains data that should be in the tables.
211 # The uniquefieldrequired hash entry is used to determine which (if any) fields
212 # must not exist in the table for this row to be inserted. If the
213 # uniquefieldrequired entry is already in the table, the existing data is not
214 # modified, unless the forceupdate hash entry is also set. Fields in the
215 # anonymous "forceupdate" hash will be forced to be updated to the default
216 # values given in the %tabledata hash.
220 # { uniquefielrequired => 'fieldname', # the primary key in the table
221 # fieldname => fieldvalue,
222 # fieldname2 => fieldvalue2,
225 systempreferences => [
227 uniquefieldrequired => 'variable',
228 variable => 'Activate_Log',
230 forceupdate => { 'explanation' => 1,
232 explanation => 'Turn Log Actions on DB On an Off',
236 uniquefieldrequired => 'variable',
237 variable => 'IndependantBranches',
239 forceupdate => { 'explanation' => 1,
241 explanation => 'Turn Branch independancy management On an Off',
245 uniquefieldrequired => 'variable',
246 variable => 'ReturnBeforeExpiry',
248 forceupdate => { 'explanation' => 1,
250 explanation => 'If Yes, Returndate on issuing can\'t be after borrower card expiry',
254 uniquefieldrequired => 'variable',
255 variable => 'opacstylesheet',
257 forceupdate => { 'explanation' => 1,
259 explanation => 'Enter a complete URL to use an alternate stylesheet in OPAC',
263 uniquefieldrequired => 'variable',
264 variable => 'opacsmallimage',
266 forceupdate => { 'explanation' => 1,
268 explanation => 'Enter a complete URL to an image, will be on top/left instead of the Koha logo',
272 uniquefieldrequired => 'variable',
273 variable => 'opaclargeimage',
275 forceupdate => { 'explanation' => 1,
277 explanation => 'Enter a complete URL to an image, will be on the main page, instead of the Koha logo',
281 uniquefieldrequired => 'variable',
282 variable => 'delimiter',
284 forceupdate => { 'explanation' => 1,
286 explanation => 'separator for reports exported to spreadsheet',
290 uniquefieldrequired => 'variable',
292 value => 'OPENOFFICE.ORG',
293 forceupdate => { 'explanation' => 1,
296 explanation => 'Define the default application for report exportations into files',
298 options => 'EXCEL|OPENOFFICE.ORG'
301 uniquefieldrequired => 'variable',
302 variable => 'Delimiter',
304 forceupdate => { 'explanation' => 1,
307 explanation => 'Define the default separator character for report exportations into files',
309 options => ';|tabulation|,|/|\|#'
312 uniquefieldrequired => 'variable',
313 variable => 'SubscriptionHistory',
315 forceupdate => { 'explanation' => 1,
318 explanation => 'Define the information level for serials history in OPAC',
320 options => 'simplified|full'
323 uniquefieldrequired => 'variable',
324 variable => 'hidelostitems',
326 forceupdate => { 'explanation' => 1,
328 explanation => 'show or hide "lost" items in OPAC.',
332 uniquefieldrequired => 'variable',
333 variable => 'IndependantBranches',
335 forceupdate => { 'explanation' => 1,
337 explanation => 'Turn Branch independancy management On an Off',
341 uniquefieldrequired => 'variable',
342 variable => 'ReturnBeforeExpiry',
344 forceupdate => { 'explanation' => 1,
346 explanation => 'If Yes, Returndate on issuing can\'t be after borrower card expiry',
350 uniquefieldrequired => 'variable',
351 variable => 'Disable_Dictionary',
353 forceupdate => { 'explanation' => 1,
355 explanation => 'Disables Dictionary buttons if set to yes',
359 uniquefieldrequired => 'variable',
360 variable => 'hide_marc',
362 forceupdate => { 'explanation' => 1,
364 explanation => 'hide marc specific datas like subfield code & indicators to library',
368 uniquefieldrequired => 'variable',
369 variable => 'NotifyBorrowerDeparture',
371 forceupdate => { 'explanation' => 1,
373 explanation => 'Delay before expiry where a notice is sent when issuing',
377 uniquefieldrequired => 'variable',
378 variable => 'OpacPasswordChange',
380 forceupdate => { 'explanation' => 1,
382 explanation => 'Enable/Disable password change in OPAC (disable it when using LDAP auth)',
386 uniquefieldrequired => 'variable',
387 variable => 'useDaysMode',
389 forceupdate => { 'explanation' => 1,
391 explanation => 'How to calculate return dates : Calendar means holidays will be controled, Days means the return date don\'t depend on holidays',
393 options => 'Calendar|Days'
396 uniquefieldrequired => 'variable',
397 variable => 'borrowerMandatoryField',
398 value => 'zipcode|surname',
399 forceupdate => { 'explanation' => 1,
401 explanation => 'List all mandatory fields for borrowers',
405 uniquefieldrequired => 'variable',
406 variable => 'borrowerRelationship',
407 value => 'father|mother,grand-mother',
408 forceupdate => { 'explanation' => 1,
410 explanation => 'The relationships between a guarantor & a guarantee (separated by | or ,)',
414 uniquefieldrequired => 'variable',
415 variable => 'ReservesMaxPickUpDelay',
417 forceupdate => { 'explanation' => 1,
419 explanation => 'Maximum delay to pick up a reserved document',
423 uniquefieldrequired => 'variable',
424 variable => 'TransfersMaxDaysWarning',
426 forceupdate => { 'explanation' => 1,
428 explanation => 'Max delay before considering the transfer has potentialy a problem',
432 uniquefieldrequired => 'variable',
433 variable => 'memberofinstitution',
435 forceupdate => { 'explanation' => 1,
437 explanation => 'Are your patrons members of institutions',
441 uniquefieldrequired => 'variable',
442 variable => 'ReadingHistory',
444 forceupdate => { 'explanation' => 1,
446 explanation => 'Allow reading record info retrievable from issues and oldissues tables',
450 uniquefieldrequired => 'variable',
451 variable => 'IssuingInProcess',
453 forceupdate => { 'explanation' => 1,
455 explanation => 'Allow no debt alert if the patron is issuing item that accumulate debt',
459 uniquefieldrequired => 'variable',
460 variable => 'AutomaticItemReturn',
462 forceupdate => { 'explanation' => 1,
464 explanation => 'This Variable allow or not to return automaticly to his homebranch',
468 uniquefieldrequired => 'variable',
469 variable => 'reviewson',
471 forceupdate => { 'explanation' => 1,
473 explanation => 'Allows patrons to submit reviews from the opac',
480 my %fielddefinitions = (
482 # { field => 'fieldname',
483 # type => 'fieldtype',
501 field => 'booksellerid',
511 field => 'listprice',
512 type => 'varchar(10)',
519 field => 'invoiceprice',
520 type => 'varchar(10)',
529 field => 'borrowernumber',
531 null => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
537 field => 'itemnumber',
539 null => 'NULL', # can be null when a borrower is deleted and the foreign key rule executed
546 { field => 'B_email',
549 after => 'B_zipcode',
552 field => 'streetnumber', # street number (hidden if streettable table is empty)
558 field => 'streettype', # street table, list builded from a system table
561 after => 'streetnumber',
564 field => 'B_streetnumber', # street number (hidden if streettable table is empty)
570 field => 'B_streettype', # street table, list builded from a system table
573 after => 'B_streetnumber',
582 field => 'address2', # complement address
594 field => 'contactfirstname', # contact's firstname
597 after => 'contactname',
600 field => 'contacttitle', # contact's title
603 after => 'contactfirstname',
607 deletedborrowers => [
608 { field => 'B_email',
611 after => 'B_zipcode',
614 field => 'streetnumber', # street number (hidden if streettable table is empty)
620 field => 'streettype', # street table, list builded from a system table
623 after => 'streetnumber',
626 field => 'B_streetnumber', # street number (hidden if streettable table is empty)
632 field => 'B_streettype', # street table, list builded from a system table
635 after => 'B_streetnumber',
644 field => 'address2', # complement address
656 field => 'contactfirstname', # contact's firstname
659 after => 'contactname',
662 field => 'contacttitle', # contact's title
665 after => 'contactfirstname',
672 type => 'varchar(15)',
679 field => 'branchprinter',
680 type => 'varchar(100)',
689 field => 'category_type',
699 field => 'waitingdate',
711 # { indexname => 'index detail'
715 { indexname => 'shelfnumber',
716 content => 'shelfnumber',
718 { indexname => 'itemnumber',
719 content => 'itemnumber',
723 { indexname => 'biblionumber',
724 content => 'biblionumber',
728 { indexname => 'homebranch',
729 content => 'homebranch',
731 { indexname => 'holdingbranch',
732 content => 'holdingbranch',
736 { indexname => 'PRIMARY',
742 { indexname => 'booksellerid',
743 content => 'booksellerid',
747 { indexname => 'basketno',
748 content => 'basketno',
751 aqorderbreakdown => [
752 { indexname => 'ordernumber',
753 content => 'ordernumber',
755 { indexname => 'bookfundid',
756 content => 'bookfundid',
760 { indexname => 'PRIMARY',
761 content => 'currency',
769 # { key => 'the key in table' (must be indexed)
770 # foreigntable => 'the foreigntable name', # (the parent)
771 # foreignkey => 'the foreign key column(s)' # (in the parent)
772 # onUpdate => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
773 # onDelete => 'CASCADE|SET NULL|NO ACTION| RESTRICT',
777 { key => 'shelfnumber',
778 foreigntable => 'bookshelf',
779 foreignkey => 'shelfnumber',
780 onUpdate => 'CASCADE',
781 onDelete => 'CASCADE',
783 { key => 'itemnumber',
784 foreigntable => 'items',
785 foreignkey => 'itemnumber',
786 onUpdate => 'CASCADE',
787 onDelete => 'CASCADE',
790 # onDelete is RESTRICT on reference tables (branches, itemtype) as we don't want items to be
791 # easily deleted, but branches/itemtype not too easy to empty...
793 { key => 'biblionumber',
794 foreigntable => 'biblio',
795 foreignkey => 'biblionumber',
796 onUpdate => 'CASCADE',
797 onDelete => 'CASCADE',
800 foreigntable => 'itemtypes',
801 foreignkey => 'itemtype',
802 onUpdate => 'CASCADE',
803 onDelete => 'RESTRICT',
807 { key => 'biblioitemnumber',
808 foreigntable => 'biblioitems',
809 foreignkey => 'biblioitemnumber',
810 onUpdate => 'CASCADE',
811 onDelete => 'CASCADE',
813 { key => 'homebranch',
814 foreigntable => 'branches',
815 foreignkey => 'branchcode',
816 onUpdate => 'CASCADE',
817 onDelete => 'RESTRICT',
819 { key => 'holdingbranch',
820 foreigntable => 'branches',
821 foreignkey => 'branchcode',
822 onUpdate => 'CASCADE',
823 onDelete => 'RESTRICT',
826 additionalauthors => [
827 { key => 'biblionumber',
828 foreigntable => 'biblio',
829 foreignkey => 'biblionumber',
830 onUpdate => 'CASCADE',
831 onDelete => 'CASCADE',
835 { key => 'biblionumber',
836 foreigntable => 'biblio',
837 foreignkey => 'biblionumber',
838 onUpdate => 'CASCADE',
839 onDelete => 'CASCADE',
843 { key => 'booksellerid',
844 foreigntable => 'aqbooksellers',
846 onUpdate => 'CASCADE',
847 onDelete => 'RESTRICT',
852 foreigntable => 'aqbasket',
853 foreignkey => 'basketno',
854 onUpdate => 'CASCADE',
855 onDelete => 'CASCADE',
857 { key => 'biblionumber',
858 foreigntable => 'biblio',
859 foreignkey => 'biblionumber',
860 onUpdate => 'SET NULL',
861 onDelete => 'SET NULL',
865 { key => 'listprice',
866 foreigntable => 'currency',
867 foreignkey => 'currency',
868 onUpdate => 'CASCADE',
869 onDelete => 'CASCADE',
871 { key => 'invoiceprice',
872 foreigntable => 'currency',
873 foreignkey => 'currency',
874 onUpdate => 'CASCADE',
875 onDelete => 'CASCADE',
878 aqorderbreakdown => [
879 { key => 'ordernumber',
880 foreigntable => 'aqorders',
881 foreignkey => 'ordernumber',
882 onUpdate => 'CASCADE',
883 onDelete => 'CASCADE',
885 { key => 'bookfundid',
886 foreigntable => 'aqbookfund',
887 foreignkey => 'bookfundid',
888 onUpdate => 'CASCADE',
889 onDelete => 'CASCADE',
893 { key => 'frombranch',
894 foreigntable => 'branches',
895 foreignkey => 'branchcode',
896 onUpdate => 'CASCADE',
897 onDelete => 'CASCADE',
900 foreigntable => 'branches',
901 foreignkey => 'branchcode',
902 onUpdate => 'CASCADE',
903 onDelete => 'CASCADE',
905 { key => 'itemnumber',
906 foreigntable => 'items',
907 foreignkey => 'itemnumber',
908 onUpdate => 'CASCADE',
909 onDelete => 'CASCADE',
913 { key => 'categorycode',
914 foreigntable => 'categories',
915 foreignkey => 'categorycode',
916 onUpdate => 'CASCADE',
917 onDelete => 'CASCADE',
920 foreigntable => 'itemtypes',
921 foreignkey => 'itemtype',
922 onUpdate => 'CASCADE',
923 onDelete => 'CASCADE',
926 issues => [ # constraint is SET NULL : when a borrower or an item is deleted, we keep the issuing record
928 { key => 'borrowernumber',
929 foreigntable => 'borrowers',
930 foreignkey => 'borrowernumber',
931 onUpdate => 'SET NULL',
932 onDelete => 'SET NULL',
934 { key => 'itemnumber',
935 foreigntable => 'items',
936 foreignkey => 'itemnumber',
937 onUpdate => 'SET NULL',
938 onDelete => 'SET NULL',
942 { key => 'borrowernumber',
943 foreigntable => 'borrowers',
944 foreignkey => 'borrowernumber',
945 onUpdate => 'CASCADE',
946 onDelete => 'CASCADE',
948 { key => 'biblionumber',
949 foreigntable => 'biblio',
950 foreignkey => 'biblionumber',
951 onUpdate => 'CASCADE',
952 onDelete => 'CASCADE',
954 { key => 'itemnumber',
955 foreigntable => 'items',
956 foreignkey => 'itemnumber',
957 onUpdate => 'CASCADE',
958 onDelete => 'CASCADE',
960 { key => 'branchcode',
961 foreigntable => 'branches',
962 foreignkey => 'branchcode',
963 onUpdate => 'CASCADE',
964 onDelete => 'CASCADE',
967 borrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
968 # but prevent deleting a branch as soon as it has 1 borrower !
969 { key => 'categorycode',
970 foreigntable => 'categories',
971 foreignkey => 'categorycode',
972 onUpdate => 'RESTRICT',
973 onDelete => 'RESTRICT',
975 { key => 'branchcode',
976 foreigntable => 'branches',
977 foreignkey => 'branchcode',
978 onUpdate => 'RESTRICT',
979 onDelete => 'RESTRICT',
982 deletedborrowers => [ # foreign keys are RESTRICT as we don't want to delete borrowers when a branch is deleted
983 # but prevent deleting a branch as soon as it has 1 borrower !
984 { key => 'categorycode',
985 foreigntable => 'categories',
986 foreignkey => 'categorycode',
987 onUpdate => 'RESTRICT',
988 onDelete => 'RESTRICT',
990 { key => 'branchcode',
991 foreigntable => 'branches',
992 foreignkey => 'branchcode',
993 onUpdate => 'RESTRICT',
994 onDelete => 'RESTRICT',
998 { key => 'borrowernumber',
999 foreigntable => 'borrowers',
1000 foreignkey => 'borrowernumber',
1001 onUpdate => 'CASCADE',
1002 onDelete => 'CASCADE',
1004 { key => 'itemnumber',
1005 foreigntable => 'items',
1006 foreignkey => 'itemnumber',
1007 onUpdate => 'SET NULL',
1008 onDelete => 'SET NULL',
1011 auth_tag_structure => [
1012 { key => 'authtypecode',
1013 foreigntable => 'auth_types',
1014 foreignkey => 'authtypecode',
1015 onUpdate => 'CASCADE',
1016 onDelete => 'CASCADE',
1019 # FIXME : don't constraint auth_*_table and auth_word, as they may be replaced by zebra
1024 my %column_change = (
1028 from => 'emailaddress',
1033 from => 'streetaddress',
1035 after => 'initials',
1038 from => 'faxnumber',
1043 from => 'textmessaging',
1049 to => 'contactnote',
1050 after => 'opacnote',
1053 from => 'physstreet',
1058 from => 'streetcity',
1060 after => 'B_address',
1073 from => 'homezipcode',
1080 after => 'B_zipcode',
1085 after => 'dateenrolled',
1088 from => 'guarantor',
1089 to => 'guarantorid',
1090 after => 'contactname',
1093 from => 'textmessaging',
1099 to => 'contactnotes',
1100 after => 'opacnotes',
1103 from => 'altrelationship',
1104 to => 'relationship',
1105 after => 'borrowernotes',
1109 deletedborrowers => [
1111 from => 'emailaddress',
1116 from => 'streetaddress',
1118 after => 'initials',
1121 from => 'faxnumber',
1126 from => 'textmessaging',
1132 to => 'contactnote',
1133 after => 'opacnote',
1136 from => 'physstreet',
1141 from => 'streetcity',
1143 after => 'B_address',
1156 from => 'homezipcode',
1163 after => 'B_zipcode',
1168 after => 'dateenrolled',
1171 from => 'guarantor',
1172 to => 'guarantorid',
1173 after => 'contactname',
1176 from => 'textmessaging',
1182 to => 'contactnotes',
1183 after => 'opacnotes',
1186 from => 'altrelationship',
1187 to => 'relationship',
1188 after => 'borrowernotes',
1194 foreach my $table (keys %column_change) {
1195 $sth = $dbh->prepare("show columns from $table");
1198 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1200 $types{$column}->{type} ="$type";
1201 $types{$column}->{null} = "$null";
1202 $types{$column}->{key} = "$key";
1203 $types{$column}->{default} = "$default";
1204 $types{$column}->{extra} = "$extra";
1206 my $tablerows = $column_change{$table};
1207 foreach my $row ( @$tablerows ) {
1208 if ($types{$row->{from}}->{type}) {
1209 print "altering $table $row->{from} to $row->{to}\n";
1210 # ALTER TABLE `borrowers` CHANGE `faxnumber` `fax` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
1211 # alter table `borrowers` change `faxnumber` `fax` type text null after phone
1213 "alter table `$table` change `$row->{from}` `$row->{to}` $types{$row->{from}}->{type} ".
1214 ($types{$row->{from}}->{null} eq 'YES'?" NULL":" NOT NULL").
1215 ($types{$row->{from}}->{default}?" default ".$types{$row->{from}}->{default}:"").
1216 "$types{$row->{from}}->{extra} after $row->{after} ";
1223 #-------------------
1228 # Get version of MySQL database engine.
1229 my $mysqlversion = `mysqld --version`;
1230 $mysqlversion =~ /Ver (\S*) /;
1232 if ( $mysqlversion ge '3.23' ) {
1233 print "Could convert to MyISAM database tables...\n" unless $silent;
1236 #---------------------------------
1239 # Collect all tables into a list
1240 $sth = $dbh->prepare("show tables");
1242 while ( my ($table) = $sth->fetchrow ) {
1243 $existingtables{$table} = 1;
1247 # Now add any missing tables
1248 foreach $table ( keys %requiretables ) {
1249 unless ( $existingtables{$table} ) {
1250 print "Adding $table table...\n" unless $silent;
1251 my $sth = $dbh->prepare("create table $table $requiretables{$table}");
1254 print "Error : $sth->errstr \n";
1260 # now drop useless tables
1261 foreach $table ( keys %dropable_table ) {
1262 if ( $existingtables{$table} ) {
1263 print "Dropping unused table $table\n" if $debug and not $silent;
1264 $dbh->do("drop table $table");
1266 print "Error : $dbh->errstr \n";
1271 #---------------------------------
1274 foreach $table ( keys %requirefields ) {
1275 print "Check table $table\n" if $debug and not $silent;
1276 $sth = $dbh->prepare("show columns from $table");
1279 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1281 $types{$column} = $type;
1283 foreach $column ( keys %{ $requirefields{$table} } ) {
1284 print " Check column $column [$types{$column}]\n" if $debug and not $silent;
1285 if ( !$types{$column} ) {
1287 # column doesn't exist
1288 print "Adding $column field to $table table...\n" unless $silent;
1289 $query = "alter table $table
1290 add column $column " . $requirefields{$table}->{$column};
1291 print "Execute: $query\n" if $debug;
1292 my $sti = $dbh->prepare($query);
1295 print "**Error : $sti->errstr \n";
1302 foreach $table ( keys %fielddefinitions ) {
1303 print "Check table $table\n" if $debug;
1304 $sth = $dbh->prepare("show columns from $table");
1307 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1309 $definitions->{$column}->{type} = $type;
1310 $definitions->{$column}->{null} = $null;
1311 $definitions->{$column}->{null} = 'NULL' if $null eq 'YES';
1312 $definitions->{$column}->{key} = $key;
1313 $definitions->{$column}->{default} = $default;
1314 $definitions->{$column}->{extra} = $extra;
1316 my $fieldrow = $fielddefinitions{$table};
1317 foreach my $row (@$fieldrow) {
1318 my $field = $row->{field};
1319 my $type = $row->{type};
1320 my $null = $row->{null};
1321 # $null = 'YES' if $row->{null} eq 'NULL';
1322 my $key = $row->{key};
1323 my $default = $row->{default};
1324 my $null = $row->{null};
1325 # $default="''" unless $default;
1326 my $extra = $row->{extra};
1327 my $def = $definitions->{$field};
1328 my $after = ($row->{after}?" after ".$row->{after}:"");
1330 unless ( $type eq $def->{type}
1331 && $null eq $def->{null}
1332 && $key eq $def->{key}
1333 && $extra eq $def->{extra} )
1335 if ( $null eq '' ) {
1338 if ( $key eq 'PRI' ) {
1339 $key = 'PRIMARY KEY';
1341 unless ( $extra eq 'auto_increment' ) {
1345 # if it's a new column use "add", if it's an old one, use "change".
1347 if ($definitions->{$field}->{type}) {
1348 $action="change $field"
1352 # if it's a primary key, drop the previous pk, before altering the table
1354 if ($key ne 'PRIMARY KEY') {
1355 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ? $after");
1357 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ? $after");
1359 $sth->execute($default);
1360 print " alter or create $field in $table\n" unless $silent;
1365 # Populate tables with required data
1368 # synch table and deletedtable.
1369 foreach my $table (('borrowers','items','biblio','biblioitems')) {
1370 my %deletedborrowers;
1371 print "synch'ing $table\n";
1372 $sth = $dbh->prepare("show columns from deleted$table");
1374 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1375 $deletedborrowers{$column}=1;
1377 $sth = $dbh->prepare("show columns from $table");
1380 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ) {
1381 unless ($deletedborrowers{$column}) {
1382 my $newcol="alter table deleted$table add $column $type";
1383 if ($null eq 'YES') {
1384 $newcol .= " NULL ";
1386 $newcol .= " NOT NULL ";
1388 $newcol .= "default $default" if $default;
1389 $newcol .= " after $previous" if $previous;
1391 print "creating column $column\n";
1397 foreach my $table ( keys %tabledata ) {
1398 print "Checking for data required in table $table...\n" unless $silent;
1399 my $tablerows = $tabledata{$table};
1400 foreach my $row (@$tablerows) {
1401 my $uniquefieldrequired = $row->{uniquefieldrequired};
1402 my $uniquevalue = $row->{$uniquefieldrequired};
1403 my $forceupdate = $row->{forceupdate};
1406 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
1408 $sth->execute($uniquevalue);
1410 foreach my $field (keys %$forceupdate) {
1411 if ($forceupdate->{$field}) {
1412 my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
1413 $sth->execute($row->{$field}, $uniquevalue);
1417 print "Adding row to $table: " unless $silent;
1421 foreach my $field ( keys %$row ) {
1422 next if $field eq 'uniquefieldrequired';
1423 next if $field eq 'forceupdate';
1424 my $value = $row->{$field};
1425 push @values, $value;
1426 print " $field => $value" unless $silent;
1427 $fieldlist .= "$field,";
1428 $placeholders .= "?,";
1430 print "\n" unless $silent;
1431 $fieldlist =~ s/,$//;
1432 $placeholders =~ s/,$//;
1435 "insert into $table ($fieldlist) values ($placeholders)");
1436 $sth->execute(@values);
1442 # check indexes and create them when needed
1444 print "Checking for index required...\n" unless $silent;
1445 foreach my $table ( keys %indexes ) {
1447 # read all indexes from $table
1449 $sth = $dbh->prepare("show index from $table");
1451 my %existingindexes;
1452 while ( my ( $table, $non_unique, $key_name, $Seq_in_index, $Column_name, $Collation, $cardinality, $sub_part, $Packed, $comment ) = $sth->fetchrow ) {
1453 $existingindexes{$key_name} = 1;
1455 # read indexes to check
1456 my $tablerows = $indexes{$table};
1457 foreach my $row (@$tablerows) {
1458 my $key_name=$row->{indexname};
1459 if ($existingindexes{$key_name} eq 1) {
1460 # print "$key_name existing";
1462 print "\tCreating index $key_name in $table\n";
1464 if ($row->{indexname} eq 'PRIMARY') {
1465 $sql = "alter table $table ADD PRIMARY KEY ($row->{content})";
1467 $sql = "alter table $table ADD INDEX $key_name ($row->{content}) $row->{type}";
1470 print "Error $sql : $dbh->err \n" if $dbh->err;
1476 # check foreign keys and create them when needed
1478 print "Checking for foreign keys required...\n" unless $silent;
1479 foreach my $table ( keys %foreign_keys ) {
1481 # read all indexes from $table
1483 $sth = $dbh->prepare("show table status like '$table'");
1485 my $stat = $sth->fetchrow_hashref;
1486 # read indexes to check
1487 my $tablerows = $foreign_keys{$table};
1488 foreach my $row (@$tablerows) {
1489 my $foreign_table=$row->{foreigntable};
1490 if ($stat->{'Comment'} =~/$foreign_table/) {
1491 # print "$foreign_table existing\n";
1493 print "\tCreating foreign key $foreign_table in $table\n";
1494 # first, drop any orphan value in child table
1495 if ($row->{onDelete} ne "RESTRICT") {
1496 my $sql = "delete from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})";
1498 print "SQL ERROR: $sql : $dbh->err \n" if $dbh->err;
1500 my $sql="alter table $table ADD FOREIGN KEY $row->{key} ($row->{key}) REFERENCES $row->{foreigntable} ($row->{foreignkey})";
1501 $sql .= " on update ".$row->{onUpdate} if $row->{onUpdate};
1502 $sql .= " on delete ".$row->{onDelete} if $row->{onDelete};
1505 print "====================
1506 An error occured during :
1508 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).
1509 You can find those values with select
1510 \t$table.* from $table where $row->{key} not in (select $row->{foreignkey} from $row->{foreigntable})
1511 ====================\n
1522 # create frameworkcode row in biblio table & fill it with marc_biblio.frameworkcode.
1525 # 1st, get how many biblio we will have to do...
1526 $sth = $dbh->prepare('select count(*) from marc_biblio');
1528 my ($totaltodo) = $sth->fetchrow;
1530 $sth = $dbh->prepare("show columns from biblio");
1533 my $bibliofwexist=0;
1534 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
1535 $bibliofwexist=1 if $column eq 'frameworkcode';
1537 unless ($bibliofwexist) {
1538 print "moving biblioframework to biblio table\n";
1539 $dbh->do('ALTER TABLE `biblio` ADD `frameworkcode` VARCHAR( 4 ) NOT NULL AFTER `biblionumber`');
1540 $sth = $dbh->prepare('select biblionumber,frameworkcode from marc_biblio');
1542 my $sth_update = $dbh->prepare('update biblio set frameworkcode=? where biblionumber=?');
1544 while (my ($biblionumber,$frameworkcode) = $sth->fetchrow) {
1545 $sth_update->execute($frameworkcode,$biblionumber);
1547 print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
1553 # moving MARC data from marc_subfield_table to biblioitems.marc
1555 $sth = $dbh->prepare("show columns from biblioitems");
1559 while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow ){
1560 $marcdone=1 if ($type eq 'blob' && $column eq 'marc') ;
1562 unless ($marcdone) {
1563 print "moving MARC record to biblioitems table\n";
1564 # changing marc field type
1565 $dbh->do('ALTER TABLE `biblioitems` CHANGE `marc` `marc` BLOB NULL DEFAULT NULL ');
1566 # adding marc xml, just for convenience
1567 $dbh->do('ALTER TABLE `biblioitems` ADD `marcxml` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ');
1568 # moving data from marc_subfield_value to biblio
1569 $sth = $dbh->prepare('select bibid,biblionumber from marc_biblio');
1571 my $sth_update = $dbh->prepare('update biblioitems set marc=?, marcxml=? where biblionumber=?');
1573 while (my ($bibid,$biblionumber) = $sth->fetchrow) {
1574 my $record = MARCgetbiblio($dbh,$bibid);
1575 #Force UTF-8 in record leader
1576 $record->encoding('UTF-8');
1577 print $record->as_formatted if ($biblionumber==3902);
1578 $sth_update->execute($record->as_usmarc(),$record->as_xml_record(),$biblionumber);
1580 print "\r$totaldone / $totaltodo" unless ($totaldone % 100);
1586 # at last, remove useless fields
1587 foreach $table ( keys %uselessfields ) {
1588 my @fields = split /,/,$uselessfields{$table};
1591 foreach my $fieldtodrop (@fields) {
1592 $fieldtodrop =~ s/\t//g;
1593 $fieldtodrop =~ s/\n//g;
1595 $sth = $dbh->prepare("show columns from $table");
1597 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
1599 $exists =1 if ($column eq $fieldtodrop);
1602 print "deleting $fieldtodrop field in $table...\n" unless $silent;
1603 my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
1610 # MOVE all tables TO UTF-8 and innoDB
1611 $sth = $dbh->prepare("show table status");
1613 while ( my $table = $sth->fetchrow_hashref ) {
1614 # if ($table->{Engine} ne 'InnoDB') {
1615 # $dbh->do("ALTER TABLE $table->{Name} TYPE = innodb");
1616 # print "moving $table->{Name} to InnoDB\n";
1618 unless ($table->{Collation} =~ /^utf8/) {
1619 $dbh->do("ALTER TABLE $table->{Name} CONVERT TO CHARACTER SET utf8");
1620 $dbh->do("ALTER TABLE $table->{Name} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci");
1621 # 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 !
1622 print "moving $table->{Name} to utf8\n";
1630 # those 2 subs are a copy of Biblio.pm, version 2.2.4
1631 # they are useful only once, for moving from 2.2 to 3.0
1632 # the MARCgetbiblio & MARCgetitem subs in Biblio.pm
1633 # are still here, but uses other tables
1634 # (the ones that are filled by updatedatabase !)
1639 # Returns MARC::Record of the biblio passed in parameter.
1640 my ( $dbh, $bibid ) = @_;
1641 my $record = MARC::Record->new();
1646 "select bibid,subfieldid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue,valuebloblink
1647 from marc_subfield_table
1648 where bibid=? order by tag,tagorder,subfieldorder
1653 "select subfieldvalue from marc_blob_subfield where blobidlink=?");
1654 $sth->execute($bibid);
1655 my $prevtagorder = 1;
1656 my $prevtag = 'XXX';
1658 my $field; # for >=10 tags
1659 my $prevvalue; # for <10 tags
1660 while ( my $row = $sth->fetchrow_hashref ) {
1662 if ( $row->{'valuebloblink'} ) { #---- search blob if there is one
1663 $sth2->execute( $row->{'valuebloblink'} );
1664 my $row2 = $sth2->fetchrow_hashref;
1666 $row->{'subfieldvalue'} = $row2->{'subfieldvalue'};
1668 if ( $row->{tagorder} ne $prevtagorder || $row->{tag} ne $prevtag ) {
1669 $previndicator .= " ";
1670 if ( $prevtag < 10 ) {
1671 if ($prevtag ne '000') {
1672 $record->add_fields( ( sprintf "%03s", $prevtag ), $prevvalue ) unless $prevtag eq "XXX"; # ignore the 1st loop
1674 $record->leader(sprintf("%24s",$prevvalue));
1678 $record->add_fields($field) unless $prevtag eq "XXX";
1681 $prevtagorder = $row->{tagorder};
1682 $prevtag = $row->{tag};
1683 $previndicator = $row->{tag_indicator};
1684 if ( $row->{tag} < 10 ) {
1685 $prevvalue = $row->{subfieldvalue};
1688 $field = MARC::Field->new(
1689 ( sprintf "%03s", $prevtag ),
1690 substr( $row->{tag_indicator} . ' ', 0, 1 ),
1691 substr( $row->{tag_indicator} . ' ', 1, 1 ),
1692 $row->{'subfieldcode'},
1693 $row->{'subfieldvalue'}
1698 if ( $row->{tag} < 10 ) {
1699 $record->add_fields( ( sprintf "%03s", $row->{tag} ),
1700 $row->{'subfieldvalue'} );
1703 $field->add_subfields( $row->{'subfieldcode'},
1704 $row->{'subfieldvalue'} );
1706 $prevtag = $row->{tag};
1707 $previndicator = $row->{tag_indicator};
1711 # the last has not been included inside the loop... do it now !
1712 if ( $prevtag ne "XXX" )
1713 { # check that we have found something. Otherwise, prevtag is still XXX and we
1714 # must return an empty record, not make MARC::Record fail because we try to
1715 # create a record with XXX as field :-(
1716 if ( $prevtag < 10 ) {
1717 $record->add_fields( $prevtag, $prevvalue );
1721 # my $field = MARC::Field->new( $prevtag, "", "", %subfieldlist);
1722 $record->add_fields($field);
1730 # Returns MARC::Record of the biblio passed in parameter.
1731 my ( $dbh, $bibid, $itemnumber ) = @_;
1732 my $record = MARC::Record->new();
1734 # search MARC tagorder
1737 "select tagorder from marc_subfield_table,marc_subfield_structure where marc_subfield_table.tag=marc_subfield_structure.tagfield and marc_subfield_table.subfieldcode=marc_subfield_structure.tagsubfield and bibid=? and kohafield='items.itemnumber' and subfieldvalue=?"
1739 $sth2->execute( $bibid, $itemnumber );
1740 my ($tagorder) = $sth2->fetchrow_array();
1742 #---- TODO : the leader is missing
1745 "select bibid,subfieldid,tag,tagorder,tag_indicator,subfieldcode,subfieldorder,subfieldvalue,valuebloblink
1746 from marc_subfield_table
1747 where bibid=? and tagorder=? order by subfieldcode,subfieldorder
1752 "select subfieldvalue from marc_blob_subfield where blobidlink=?");
1753 $sth->execute( $bibid, $tagorder );
1754 while ( my $row = $sth->fetchrow_hashref ) {
1755 if ( $row->{'valuebloblink'} ) { #---- search blob if there is one
1756 $sth2->execute( $row->{'valuebloblink'} );
1757 my $row2 = $sth2->fetchrow_hashref;
1759 $row->{'subfieldvalue'} = $row2->{'subfieldvalue'};
1761 if ( $record->field( $row->{'tag'} ) ) {
1764 #--- this test must stay as this, because of strange behaviour of mySQL/Perl DBI with char var containing a number...
1765 #--- sometimes, eliminates 0 at beginning, sometimes no ;-\\\
1766 if ( length( $row->{'tag'} ) < 3 ) {
1767 $row->{'tag'} = "0" . $row->{'tag'};
1769 $field = $record->field( $row->{'tag'} );
1772 $field->add_subfields( $row->{'subfieldcode'},
1773 $row->{'subfieldvalue'} );
1774 $record->delete_field($field);
1775 $record->add_fields($field);
1779 if ( length( $row->{'tag'} ) < 3 ) {
1780 $row->{'tag'} = "0" . $row->{'tag'};
1783 MARC::Field->new( $row->{'tag'}, " ", " ",
1784 $row->{'subfieldcode'} => $row->{'subfieldvalue'} );
1785 $record->add_fields($temp);
1796 # Revision 1.148 2006/06/17 22:12:01 rangi
1797 # Adding id field to reviews table
1799 # Revision 1.147 2006/06/17 03:36:41 rangi
1800 # Table definition for the reviews table
1802 # Revision 1.146 2006/06/17 03:29:41 rangi
1803 # Variable to allow librarians to switch reviews on or off
1805 # Revision 1.145 2006/06/16 09:45:02 btoumi
1806 # updatedatabase.pl: add change of borrowers table to deletedborrowers table
1807 # deletemem.pl: delete use of warn function
1809 # Revision 1.144 2006/06/08 15:36:31 alaurin
1810 # Add a new system preference 'AutomaticItemReturn' :
1812 # if this prefence is switched on: the document returned in another library than homebranch, the system automaticly transfer the document to his homebranch (with notification for librarian in returns.tmpl) .
1814 # switch off : the document stay in the holdingbranch ...
1817 # - comment C4::acquisition (not using in request.pl).
1818 # - correcting date in request.pl
1819 # -add the new call of function getbranches in request.pl
1821 # Revision 1.143 2006/06/07 02:02:47 bob_lyon
1822 # merging katipo changes...
1824 # adding new preference IssuingInProcess
1826 # Revision 1.142 2006/06/06 23:42:46 bob_lyon
1827 # Merging Katipo changes...
1829 # Adding new system pref where one can still retrieve a correct reading
1830 # record history if one has moved older data from issues to oldissues table
1831 # to speed up issues speed
1833 # Revision 1.141 2006/06/01 03:18:11 rangi
1834 # Adding a new column to the statistics table
1836 # Revision 1.140 2006/05/22 22:40:45 rangi
1837 # Adding new systempreference allowing for the library to add borrowers to institutions (rest homes, parishes, schools, classes etc).
1839 # Revision 1.139 2006/05/19 19:31:29 tgarip1957
1840 # Added new fields to auth_header and auth_subfield_table to allow ZEBRA use of authorities and new MARC framework like structure.
1841 # Authority tables are modified to be compatible with new MARC frameworks. This change is part of Authority Linking & Zebra authorities. Requires change in Mysql database. It will break head unless all changes regarding this is implemented. This warning will take place on all commits regarding this
1843 # Revision 1.138 2006/05/19 16:51:44 alaurin
1844 # update database for :
1845 # - new feature ip and printer management
1846 # adding two fields in branches table (branchip,branchprinter)
1848 # - waiting date : adding one field in reserves table(waiting date) to calculate the Maximum delay to pick up a reserved document when it's available
1850 # new system preference :
1851 # - ReservesMaxPickUpDelay : Maximum delay to pick up a reserved document
1852 # TransfersMaxDaysWarning : Max delay before considering the transfer as potentialy a problem
1854 # Revision 1.137 2006/04/18 09:36:36 plg
1855 # bug fixed: typo fixed in labels and labels_conf tables creation query.
1857 # Revision 1.136 2006/04/17 21:55:33 sushi
1858 # Added 'labels' and 'labels_conf' tables, for spine lable tool.
1860 # Revision 1.135 2006/04/15 02:37:03 tgarip1957
1861 # Marc record should be set to UTF-8 in leader.Force it.
1862 # XML should be with<record> wrappers
1864 # Revision 1.134 2006/04/14 09:37:29 tipaul
1865 # improvements from SAN Ouest Provence :
1866 # * introducing a category_type into categories. It can be A (adult), C (children), P (Professionnal), I (institution/organisation).
1867 # * each category_type has it's own forms to create members.
1868 # * the borrowers table has been heavily modified (many fields changed), to get something more logic & readable
1869 # * reintroducing guarantor/guanrantee system that is now independant from hardcoded C/A for categories
1870 # * updating templates to fit template rules
1872 # (see mail feb, 17 on koha-devel "new features for borrowers" for more details)
1874 # Revision 1.133 2006/04/13 08:36:42 plg
1875 # new: function C4::Date::get_date_format_string_for_DHTMLcalendar based on
1876 # the system preference prefered date format.
1878 # improvement: book fund list and budget list screen redesigned. Filters on
1879 # each field. Columns are not sortable yet. Using DHTML Calendar to fill date
1880 # fields instead of manual filling. Pagination system. From the book fund
1881 # list, you can reach the budget list, filtered on a book fund, or not. A
1882 # budget can be added only from book fund list screen.
1884 # bug fixed: branchcode was missing in table aqbudget.
1886 # bug fixed: when setting a branchcode to a book fund, all associated budgets
1887 # move to this branchcode.
1889 # modification: when adding/modifying budget/fund, MySQL specific "REPLACE..."
1890 # statements replaced by standard SQL compliant statement.
1892 # bug fixed: when adding/modifying a budget, if the book fund is associated to
1893 # a branch, the branch selection is disabled and set to the book fund branch.
1895 # Revision 1.132 2006/04/06 12:37:05 hdl
1896 # Bugfixing : aqbookfund needed a field.
1898 # Revision 1.131 2006/03/03 17:02:22 tipaul
1899 # commit for holidays and news management.
1900 # (some forgotten files)
1902 # Revision 1.130 2006/03/03 16:35:21 tipaul
1903 # commit for holidays and news management.
1905 # Contrib from Tümer Garip (from Turkey) :
1907 # in /tools/ the holiday.pl script let you define holidays (days where the library is closed), branch by branch. You can define 3 types of holidays :
1908 # - single day : only this day is closed
1909 # - repet weekly (like "sunday") : the day is holiday every week
1910 # - repet yearly (like "July, 4") : this day is closed every year.
1912 # You can also put exception :
1913 # - sunday is holiday, but "2006 March, 5th" the library will be open
1915 # The holidays are used for return date calculation : the return date is set to the next date where the library is open. A systempreference (useDaysMode) set ON (Calendar) or OFF (Normal) the calendar calculation.
1917 # Revision 1.129 2006/02/27 18:19:33 hdl
1918 # New table used in overduerules.pl tools page.
1920 # Revision 1.128 2006/01/25 15:16:06 tipaul
1922 # * removing useless tables
1923 # * adding useful indexes
1924 # * altering some columns definitions
1925 # * The goal being to have updater working fine for foreign keys.
1927 # For me it's done, let me know if it works for you. You can see an updated schema of the DB (with constraints) on the wiki
1929 # Revision 1.127 2006/01/24 17:57:17 tipaul
1930 # DB improvements : adding foreign keys on some tables. partial stuff done.
1932 # Revision 1.126 2006/01/06 16:39:42 tipaul
1933 # synch'ing head and rel_2_2 (from 2.2.5, including npl templates)
1934 # Seems not to break too many things, but i'm probably wrong here.
1935 # at least, new features/bugfixes from 2.2.5 are here (tested on some features on my head local copy)
1937 # - removing useless directories (koha-html and koha-plucene)
1939 # Revision 1.125 2006/01/04 15:54:55 tipaul
1940 # utf8 is a : go for beta test in HEAD.
1941 # some explanations :
1942 # - updater/updatedatabase => will transform all tables in innoDB (not related to utf8, just to warn you) AND collate them in utf8 / utf8_general_ci. The SQL command is : ALTER TABLE tablename DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci.
1943 # - *-top.inc will show the pages in utf8
1944 # - THE HARD THING : for me, mysql-client and mysql-server were set up to communicate in iso8859-1, whatever the mysql collation ! Thus, pages were improperly shown, as datas were transmitted in iso8859-1 format ! After a full day of investigation, someone on usenet pointed "set NAMES 'utf8'" to explain that I wanted utf8. I could put this in my.cnf, but if I do that, ALL databases will "speak" in utf8, that's not what we want. Thus, I added a line in Context.pm : everytime a DB handle is opened, the communication is set to utf8.
1945 # - using marcxml field and no more the iso2709 raw marc biblioitems.marc field.
1947 # Revision 1.124 2005/10/27 12:09:05 tipaul
1948 # new features for serial module :
1949 # - the last 5 issues are now shown, and their status can be changed (but not reverted to "waited", as there can be only one "waited")
1950 # - the library can create a "distribution list". this paper contains a list of borrowers (selected from the borrower list, or manually entered), and print it for a given issue. once printed, the sheet can be put on the issue and distributed to every reader on the list (one by one).
1952 # Revision 1.123 2005/10/26 09:13:37 tipaul
1953 # big commit, still breaking things...
1955 # * synch with rel_2_2. Probably the last non manual synch, as rel_2_2 should not be modified deeply.
1956 # * code cleaning (cleaning warnings from perl -w) continued
1958 # Revision 1.122 2005/09/02 14:18:38 tipaul
1959 # new feature : image for itemtypes.
1961 # * run updater/updatedatabase to create imageurl field in itemtypes.
1962 # * go to Koha >> parameters >> itemtypes >> modify (or add) an itemtype. You will see around 20 nice images to choose between (thanks to owen). If you prefer your own image, you also can type a complete url (http://www.myserver.lib/path/to/my/image.gif)
1963 # * go to OPAC, and search something. In the result list, you now have the picture instead of the text itemtype.
1965 # Revision 1.121 2005/08/24 08:49:03 hdl
1966 # Adding a note field in serial table.
1967 # This will allow librarian to mention a note on a peculiar waiting serial number.
1969 # Revision 1.120 2005/08/09 14:10:32 tipaul
1970 # 1st commit to go to zebra.
1971 # don't update your cvs if you want to have a working head...
1973 # this commit contains :
1974 # * updater/updatedatabase : get rid with marc_* tables, but DON'T remove them. As a lot of things uses them, it would not be a good idea for instance to drop them. If you really want to play, you can rename them to test head without them but being still able to reintroduce them...
1975 # * Biblio.pm : modify MARCgetbiblio to find the raw marc record in biblioitems.marc field, not from marc_subfield_table, modify MARCfindframeworkcode to find frameworkcode in biblio.frameworkcode, modify some other subs to use biblio.biblionumber & get rid of bibid.
1976 # * other files : get rid of bibid and use biblionumber instead.
1979 # * does not do anything on zebra yet.
1980 # * if you rename marc_subfield_table, you can't search anymore.
1981 # * you can view a biblio & bibliodetails, go to MARC editor, but NOT save any modif.
1982 # * don't try to add a biblio, it would add data poorly... (don't try to delete either, it may work, but that would be a surprise ;-) )
1984 # IMPORTANT NOTE : you need MARC::XML package (http://search.cpan.org/~esummers/MARC-XML-0.7/lib/MARC/File/XML.pm), that requires a recent version of MARC::Record
1985 # Updatedatabase stores the iso2709 data in biblioitems.marc field & an xml version in biblioitems.marcxml Not sure we will keep it when releasing the stable version, but I think it's a good idea to have something readable in sql, at least for development stage.
1987 # Revision 1.119 2005/08/04 16:07:58 tipaul
1988 # Synch really broke this script...
1990 # Revision 1.118 2005/08/04 16:02:55 tipaul
1991 # oops... error in synch between 2.2 and head
1993 # Revision 1.117 2005/08/04 14:24:39 tipaul
1994 # synch'ing 2.2 and head
1996 # Revision 1.116 2005/08/04 08:55:54 tipaul
1997 # Letters / alert system, continuing...
1999 # * adding a package Letters.pm, that manages Letters & alerts.
2000 # * adding feature : it's now possible to define a "letter" for any subscription created. If a letter is defined, users in OPAC can put an alert on the subscription. When an issue is marked "arrived", all users in the alert will recieve a mail (as defined in the "letter"). This last part (= send the mail) is not yet developped. (Should be done this week)
2001 # * adding feature : it's now possible to "put to an alert" in OPAC, for any serial subscription. The alert is stored in a new table, called alert. An alert can be put only if the librarian has activated them in subscription (and they activate it just by choosing a "letter" to sent to borrowers on new issues)
2002 # * adding feature : librarian can see in borrower detail which alerts they have put, and a user can see in opac-detail which alert they have put too.
2004 # Note that the system should be generic enough to manage any type of alert.
2005 # I plan to extend it soon to virtual shelves : a borrower will be able to put an alert on a virtual shelf, to be warned when something is changed in the virtual shelf (mail being sent once a day by cron, or manually by the shelf owner. Anyway, a mail won't be sent on every change, users would be spammed by Koha ;-) )
2007 # Revision 1.115 2005/08/02 16:15:34 tipaul
2008 # adding 2 fields to letter system :
2009 # * module (acquisition, catalogue...) : it will be usefull to show the librarian only letters he may be interested by.
2010 # * title, that will be used as mail subject.
2012 # Revision 1.114 2005/07/28 15:10:13 tipaul
2013 # Introducing new "Letters" system : Letters will be used everytime you want to sent something to someone (through mail or paper). For example, sending a mail for overdues use letter that you can put as parameters. Sending a mail to a borrower when a suggestion is validated uses a letter too.
2014 # the letter table contains 3 fields :
2015 # * code => the code of the letter
2016 # * name => the complete name of the letter
2017 # * content => the complete text. It's a TEXT field type, so has no limits.
2019 # My next goal now is to work on point 2-I "serial issue alert"
2020 # With this feature, in serials, a user can subscribe the "issue alert". For every issue arrived/missing, a mail is sent to all subscribers of this list. The mail warns the user that the issue is arrive or missing. Will be in head.
2021 # (see mail on koha-devel, 2005/04/07)
2023 # The "serial issue alert" will be the 1st to use this letter system that probably needs some tweaking ;-)
2025 # Once it will be stabilised default letters (in any languages) could be added during installer to help the library begin with this new feature.
2027 # Revision 1.113 2005/07/28 08:38:41 tipaul
2028 # For instance, the return date does not rely on the borrower expiration date. A systempref will be added in Koha, to modify return date calculation schema :
2029 # * ReturnBeforeExpiry = yes => return date can't be after expiry date
2030 # * ReturnBeforeExpiry = no => return date can be after expiry date
2032 # Revision 1.112 2005/07/26 08:19:47 hdl
2033 # Adding IndependantBranches System preference variable in order to manage Branch independancy.
2035 # Revision 1.111 2005/07/25 15:35:38 tipaul
2036 # we have decided that moving to Koha 3.0 requires being already in Koha 2.2.x
2037 # So, the updatedatabase script can highly be cleaned (90% removed).
2038 # Let's play with the new Koha DB structure now ;-)