we have decided that moving to Koha 3.0 requires being already in Koha 2.2.x
[koha.git] / updater / updatedatabase
1 #!/usr/bin/perl
2
3 # $Id$
4
5 # Database Updater
6 # This script checks for required updates to the database.
7
8 # Part of the Koha Library Software www.koha.org
9 # Licensed under the GPL.
10
11 # Bugs/ToDo:
12 # - Would also be a good idea to offer to do a backup at this time...
13
14 # NOTE:  If you do something more than once in here, make it table driven.
15 use strict;
16
17 # CPAN modules
18 use DBI;
19 use Getopt::Long;
20 # Koha modules
21 use C4::Context;
22
23 # FIXME - The user might be installing a new database, so can't rely
24 # on /etc/koha.conf anyway.
25
26 my $debug = 0;
27
28 my (
29     $sth, $sti,
30     $query,
31     %existingtables,    # tables already in database
32     %types,
33     $table,
34     $column,
35     $type, $null, $key, $default, $extra,
36     $prefitem,          # preference item in systempreferences table
37 );
38
39 my $silent;
40 GetOptions(
41         's' =>\$silent
42         );
43 my $dbh = C4::Context->dbh;
44 print "connected to your DB. Checking & modifying it\n" unless $silent;
45
46 #-------------------
47 # Defines
48
49 # Tables to add if they don't exist
50 my %requiretables = (
51     categorytable       => "(categorycode char(5) NOT NULL default '',
52                              description text default '',
53                              itemtypecodes text default '',
54                              PRIMARY KEY (categorycode)
55                             )",
56     subcategorytable       => "(subcategorycode char(5) NOT NULL default '',
57                              description text default '',
58                              itemtypecodes text default '',
59                              PRIMARY KEY (subcategorycode)
60                             )",
61     mediatypetable       => "(mediatypecode char(5) NOT NULL default '',
62                              description text default '',
63                              itemtypecodes text default '',
64                              PRIMARY KEY (mediatypecode)
65                             )",
66     action_logs         => "(
67                                     `timestamp` TIMESTAMP NOT NULL ,
68                                     `user` INT( 11 ) NOT NULL ,
69                                     `module` TEXT default '',
70                                     `action` TEXT default '' ,
71                                     `object` INT(11) default '' ,
72                                     `info` TEXT default '' ,
73                                     PRIMARY KEY ( `timestamp` , `user` )
74                             )",
75 );
76
77 my %requirefields = (
78 #    tablename        => { 'field' => 'fieldtype' },
79 );
80
81 my %dropable_table = (
82 # tablename => 'tablename',
83 );
84
85 my %uselessfields = (
86 # tablename => "field1,field2",
87         );
88 # the other hash contains other actions that can't be done elsewhere. they are done
89 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
90
91 # The tabledata hash contains data that should be in the tables.
92 # The uniquefieldrequired hash entry is used to determine which (if any) fields
93 # must not exist in the table for this row to be inserted.  If the
94 # uniquefieldrequired entry is already in the table, the existing data is not
95 # modified, unless the forceupdate hash entry is also set.  Fields in the
96 # anonymous "forceupdate" hash will be forced to be updated to the default
97 # values given in the %tabledata hash.
98
99 my %tabledata = (
100 # tablename => [
101 #       {       uniquefielrequired => 'fieldname', # the primary key in the table
102 #               fieldname => fieldvalue,
103 #               fieldname2 => fieldvalue2,
104 #       },
105 # ],
106     systempreferences => [
107                 {
108             uniquefieldrequired => 'variable',
109             variable            => 'Activate_Log',
110             value               => 'On',
111             forceupdate         => { 'explanation' => 1,
112                                      'type' => 1},
113             explanation         => 'Turn Log Actions on DB On an Off',
114             type                => 'YesNo',
115         },
116     ],
117
118 );
119
120 my %fielddefinitions = (
121 # fieldname => [
122 #       {                 field => 'fieldname',
123 #             type    => 'fieldtype',
124 #             null    => '',
125 #             key     => '',
126 #             default => ''
127 #         },
128 #     ],
129 );
130
131 #-------------------
132 # Initialize
133
134 # Start checking
135
136 # Get version of MySQL database engine.
137 my $mysqlversion = `mysqld --version`;
138 $mysqlversion =~ /Ver (\S*) /;
139 $mysqlversion = $1;
140 if ( $mysqlversion ge '3.23' ) {
141     print "Could convert to MyISAM database tables...\n" unless $silent;
142 }
143
144 #---------------------------------
145 # Tables
146
147 # Collect all tables into a list
148 $sth = $dbh->prepare("show tables");
149 $sth->execute;
150 while ( my ($table) = $sth->fetchrow ) {
151     $existingtables{$table} = 1;
152 }
153
154
155 # Now add any missing tables
156 foreach $table ( keys %requiretables ) {
157     unless ( $existingtables{$table} ) {
158         print "Adding $table table...\n" unless $silent;
159         my $sth = $dbh->prepare("create table $table $requiretables{$table}");
160         $sth->execute;
161         if ( $sth->err ) {
162             print "Error : $sth->errstr \n";
163             $sth->finish;
164         }    # if error
165     }    # unless exists
166 }    # foreach
167
168 # now drop useless tables
169 foreach $table ( keys %dropable_table ) {
170         if ( $existingtables{$table} ) {
171                 print "Dropping unused table $table\n" if $debug and not $silent;
172                 $dbh->do("drop table $table");
173                 if ( $dbh->err ) {
174                         print "Error : $dbh->errstr \n";
175                 }
176         }
177 }
178
179 #---------------------------------
180 # Columns
181
182 foreach $table ( keys %requirefields ) {
183     print "Check table $table\n" if $debug and not $silent;
184     $sth = $dbh->prepare("show columns from $table");
185     $sth->execute();
186     undef %types;
187     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
188     {
189         $types{$column} = $type;
190     }    # while
191     foreach $column ( keys %{ $requirefields{$table} } ) {
192         print "  Check column $column  [$types{$column}]\n" if $debug and not $silent;
193         if ( !$types{$column} ) {
194
195             # column doesn't exist
196             print "Adding $column field to $table table...\n" unless $silent;
197             $query = "alter table $table
198                         add column $column " . $requirefields{$table}->{$column};
199             print "Execute: $query\n" if $debug;
200             my $sti = $dbh->prepare($query);
201             $sti->execute;
202             if ( $sti->err ) {
203                 print "**Error : $sti->errstr \n";
204                 $sti->finish;
205             }    # if error
206         }    # if column
207     }    # foreach column
208 }    # foreach table
209
210 foreach $table ( keys %fielddefinitions ) {
211         print "Check table $table\n" if $debug;
212         $sth = $dbh->prepare("show columns from $table");
213         $sth->execute();
214         my $definitions;
215         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
216         {
217                 $definitions->{$column}->{type}    = $type;
218                 $definitions->{$column}->{null}    = $null;
219                 $definitions->{$column}->{key}     = $key;
220                 $definitions->{$column}->{default} = $default;
221                 $definitions->{$column}->{extra}   = $extra;
222         }    # while
223         my $fieldrow = $fielddefinitions{$table};
224         foreach my $row (@$fieldrow) {
225                 my $field   = $row->{field};
226                 my $type    = $row->{type};
227                 my $null    = $row->{null};
228                 my $key     = $row->{key};
229                 my $default = $row->{default};
230                 $default="''" unless $default;
231                 my $extra   = $row->{extra};
232                 my $def     = $definitions->{$field};
233                 unless ( $type eq $def->{type}
234                         && $null eq $def->{null}
235                         && $key eq $def->{key}
236                         && $default eq $def->{default}
237                         && $extra eq $def->{extra} )
238                 {
239
240                         if ( $null eq '' ) {
241                                 $null = 'NOT NULL';
242                         }
243                         if ( $key eq 'PRI' ) {
244                                 $key = 'PRIMARY KEY';
245                         }
246                         unless ( $extra eq 'auto_increment' ) {
247                                 $extra = '';
248                         }
249                         # if it's a new column use "add", if it's an old one, use "change".
250                         my $action;
251                         if ($definitions->{$field}->{type}) {
252                                 $action="change $field"
253                         } else {
254                                 $action="add";
255                         }
256 # if it's a primary key, drop the previous pk, before altering the table
257                         my $sth;
258                         if ($key ne 'PRIMARY KEY') {
259                                 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
260                         } else {
261                                 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
262                         }
263                         $sth->execute($default);
264                         print "  Alter $field in $table\n" unless $silent;
265                 }
266         }
267 }
268
269
270 # Populate tables with required data
271 foreach my $table ( keys %tabledata ) {
272     print "Checking for data required in table $table...\n" unless $silent;
273     my $tablerows = $tabledata{$table};
274     foreach my $row (@$tablerows) {
275         my $uniquefieldrequired = $row->{uniquefieldrequired};
276         my $uniquevalue         = $row->{$uniquefieldrequired};
277         my $forceupdate         = $row->{forceupdate};
278         my $sth                 =
279           $dbh->prepare(
280 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
281         );
282         $sth->execute($uniquevalue);
283         if ($sth->rows) {
284             foreach my $field (keys %$forceupdate) {
285                 if ($forceupdate->{$field}) {
286                     my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
287                     $sth->execute($row->{$field}, $uniquevalue);
288                 }
289             }
290         } else {
291             print "Adding row to $table: " unless $silent;
292             my @values;
293             my $fieldlist;
294             my $placeholders;
295             foreach my $field ( keys %$row ) {
296                 next if $field eq 'uniquefieldrequired';
297                 next if $field eq 'forceupdate';
298                 my $value = $row->{$field};
299                 push @values, $value;
300                 print "  $field => $value" unless $silent;
301                 $fieldlist .= "$field,";
302                 $placeholders .= "?,";
303             }
304             print "\n" unless $silent;
305             $fieldlist    =~ s/,$//;
306             $placeholders =~ s/,$//;
307             my $sth =
308               $dbh->prepare(
309                 "insert into $table ($fieldlist) values ($placeholders)");
310             $sth->execute(@values);
311         }
312     }
313 }
314
315 # at last, remove useless fields
316 foreach $table ( keys %uselessfields ) {
317         my @fields = split /,/,$uselessfields{$table};
318         my $fields;
319         my $exists;
320         foreach my $fieldtodrop (@fields) {
321                 $fieldtodrop =~ s/\t//g;
322                 $fieldtodrop =~ s/\n//g;
323                 $exists =0;
324                 $sth = $dbh->prepare("show columns from $table");
325                 $sth->execute;
326                 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
327                 {
328                         $exists =1 if ($column eq $fieldtodrop);
329                 }
330                 if ($exists) {
331                         print "deleting $fieldtodrop field in $table...\n" unless $silent;
332                         my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
333                         $sth->execute;
334                 }
335         }
336 }    # foreach
337
338
339 $sth->finish;
340
341 exit;
342
343 # $Log$
344 # Revision 1.111  2005/07/25 15:35:38  tipaul
345 # we have decided that moving to Koha 3.0 requires being already in Koha 2.2.x
346 # So, the updatedatabase script can highly be cleaned (90% removed).
347 # Let's play with the new Koha DB structure now ;-)
348 #