]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 347083: Move the rest of checksetup's DB-modification code into a module
authormkanat%bugzilla.org <>
Thu, 3 Aug 2006 09:08:10 +0000 (09:08 +0000)
committermkanat%bugzilla.org <>
Thu, 3 Aug 2006 09:08:10 +0000 (09:08 +0000)
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> (module owner) a=justdave

Bugzilla/Install/DB.pm
Bugzilla/Install/Filesystem.pm
checksetup.pl

index c30dbf2ddf19576ecfb1bf521fd2ed7b85c3abd4..1e8dcb6935cb6b771ce8e10efff14eb3c5abc657 100644 (file)
@@ -32,7 +32,7 @@ use Date::Format;
 use IO::File;
 
 use base qw(Exporter);
-our @EXPORT = qw(
+our @EXPORT_OK = qw(
     indicate_progress
 );
 
@@ -43,11 +43,69 @@ sub indicate_progress {
     my $every   = $params->{every} || 1;
 
     print "." if !($current % $every);
-    if ($current % ($every * 50) == 0) {
+    if ($current % ($every * 60) == 0) {
         print "$current/$total (" . int($current * 100 / $total) . "%)\n";
     }
 }
 
+# NOTE: This is NOT the function for general table updates. See
+# update_table_definitions for that. This is only for the fielddefs table.
+sub update_fielddefs_definition {
+    my $dbh = Bugzilla->dbh;
+
+    # 2005-02-21 - LpSolit@gmail.com - Bug 279910
+    # qacontact_accessible and assignee_accessible field names no longer exist
+    # in the 'bugs' table. Their corresponding entries in the 'bugs_activity'
+    # table should therefore be marked as obsolete, meaning that they cannot
+    # be used anymore when querying the database - they are not deleted in
+    # order to keep track of these fields in the activity table.
+    if (!$dbh->bz_column_info('fielddefs', 'obsolete')) {
+        $dbh->bz_add_column('fielddefs', 'obsolete',
+            {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'});
+        print "Marking qacontact_accessible and assignee_accessible as",
+              " obsolete fields...\n";
+        $dbh->do("UPDATE fielddefs SET obsolete = 1
+                  WHERE name = 'qacontact_accessible'
+                        OR name = 'assignee_accessible'");
+    }
+
+    # 2005-08-10 Myk Melez <myk@mozilla.org> bug 287325
+    # Record each field's type and whether or not it's a custom field,
+    # in fielddefs.
+    $dbh->bz_add_column('fielddefs', 'type',
+                        {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0});
+    $dbh->bz_add_column('fielddefs', 'custom',
+        {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'});
+
+    $dbh->bz_add_column('fielddefs', 'enter_bug',
+        {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'});
+
+    # Change the name of the fieldid column to id, so that fielddefs
+    # can use Bugzilla::Object easily. We have to do this up here, because
+    # otherwise adding these field definitions will fail.
+    $dbh->bz_rename_column('fielddefs', 'fieldid', 'id');
+
+    # If the largest fielddefs sortkey is less than 100, then
+    # we're using the old sorting system, and we should convert
+    # it to the new one before adding any new definitions.
+    if (!$dbh->selectrow_arrayref(
+            'SELECT COUNT(id) FROM fielddefs WHERE sortkey >= 100'))
+    {
+        print "Updating the sortkeys for the fielddefs table...\n";
+        my $field_ids = $dbh->selectcol_arrayref(
+            'SELECT id FROM fielddefs ORDER BY sortkey');
+        my $sortkey = 100;
+        foreach my $field_id (@$field_ids) {
+            $dbh->do('UPDATE fielddefs SET sortkey = ? WHERE id = ?',
+                     undef, $sortkey, $field_id);
+            $sortkey += 100;
+        }
+    }
+
+    # Remember, this is not the function for adding general table changes.
+    # That is below. Add new changes to the fielddefs table above this
+    # comment.
+}
 
 # Small changes can be put directly into this function.
 # However, larger changes (more than three or four lines) should
@@ -326,7 +384,79 @@ sub update_table_definitions {
     _initialize_dependency_tree_changes_email_pref();
     _change_all_mysql_booleans_to_tinyint();
 
+    # make classification_id field type be consistent with DB:Schema
+    $dbh->bz_alter_column('products', 'classification_id',
+                          {TYPE => 'INT2', NOTNULL => 1, DEFAULT => '1'});
+
+    # initialowner was accidentally NULL when we checked-in Schema,
+    # when it really should be NOT NULL.
+    $dbh->bz_alter_column('components', 'initialowner',
+                          {TYPE => 'INT3', NOTNULL => 1}, 0);
+
+    # 2005-03-28 - bug 238800 - index flags.type_id for editflagtypes.cgi
+    $dbh->bz_add_index('flags', 'flags_type_id_idx', [qw(type_id)]);
+
+    # For a short time, the flags_type_id_idx was misnamed in upgraded installs.
+    $dbh->bz_drop_index('flags', 'type_id');
+
+    # 2005-04-28 - LpSolit@gmail.com - Bug 7233: add an index to versions
+    $dbh->bz_alter_column('versions', 'value',
+                          {TYPE => 'varchar(64)', NOTNULL => 1});
+    $dbh->bz_add_index('versions', 'versions_product_id_idx',
+                       {TYPE => 'UNIQUE', FIELDS => [qw(product_id value)]});
 
+    if (!exists $dbh->bz_column_info('milestones', 'sortkey')->{DEFAULT}) {
+        $dbh->bz_alter_column('milestones', 'sortkey',
+                              {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0});
+    }
+
+    # 2005-06-14 - LpSolit@gmail.com - Bug 292544
+    $dbh->bz_alter_column('bugs', 'creation_ts', {TYPE => 'DATETIME'});
+
+    _fix_whine_queries_title_and_op_sys_value();
+    _fix_attachments_submitter_id_idx();
+    _copy_attachments_thedata_to_attach_data();
+    _fix_broken_all_closed_series();
+
+    # PUBLIC is a reserved word in Oracle.
+    $dbh->bz_rename_column('series', 'public', 'is_public');
+
+    # 2005-09-28 bugreport@peshkin.net Bug 149504
+    $dbh->bz_add_column('attachments', 'isurl',
+                        {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0});
+
+    # 2005-10-21 LpSolit@gmail.com - Bug 313020
+    $dbh->bz_add_column('namedqueries', 'query_type',
+                        {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0});
+
+    # 2005-11-04 LpSolit@gmail.com - Bug 305927
+    $dbh->bz_alter_column('groups', 'userregexp',
+                          {TYPE => 'TINYTEXT', NOTNULL => 1, DEFAULT => "''"});
+
+    # 2005-09-26 - olav@bkor.dhs.org - Bug 119524
+    $dbh->bz_alter_column('logincookies', 'cookie',
+        {TYPE => 'varchar(16)', PRIMARYKEY => 1, NOTNULL => 1}); 
+
+    _clean_control_characters_from_short_desc();
+    
+    # 2005-12-07 altlst@sonic.net -- Bug 225221
+    $dbh->bz_add_column('longdescs', 'comment_id',
+        {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1});
+
+    _stop_storing_inactive_flags();
+    _change_short_desc_from_mediumtext_to_varchar();
+
+    # 2006-07-01 wurblzap@gmail.com -- Bug 69000
+    $dbh->bz_add_column('namedqueries', 'id',
+        {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1});
+    _move_namedqueries_linkinfooter_to_its_own_table();
+
+    _add_classifications_sortkey();
+    _move_data_nomail_into_db();
+    
+    ################################################################
+    # New --TABLE-- changes should go *** A B O V E *** this point #
+    ################################################################
 }
 
 # Subroutines should be ordered in the order that they are called.
@@ -2148,6 +2278,378 @@ sub _change_all_mysql_booleans_to_tinyint {
    }
 }
 
+sub _fix_whine_queries_title_and_op_sys_value {
+    my $dbh = Bugzilla->dbh;
+    if (!exists $dbh->bz_column_info('whine_queries', 'title')->{DEFAULT}) {
+        # The below change actually has nothing to do with the whine_queries
+        # change, it just has to be contained within a schema change so that
+        # it doesn't run every time we run checksetup.
+
+        # Old Bugzillas have "other" as an OS choice, new ones have "Other"
+        # (capital O).
+        print "Setting any 'other' op_sys to 'Other'...\n";
+        $dbh->do('UPDATE op_sys SET value = ? WHERE value = ?',
+                 undef, "Other", "other");
+        $dbh->do('UPDATE bugs SET op_sys = ? WHERE op_sys = ?',
+                 undef, "Other", "other");
+        if (Bugzilla->params->{'defaultopsys'} eq 'other') {
+            # We can't actually fix the param here, because WriteParams() will
+            # make $datadir/params unwriteable to the webservergroup.
+            # It's too much of an ugly hack to copy the permission-fixing code
+            # down to here. (It would create more potential future bugs than
+            # it would solve problems.)
+            print "WARNING: Your 'defaultopsys' param is set to 'other', but"
+                . " Bugzilla now\n"
+                . "         uses 'Other' (capital O).\n";
+        }
+
+        # Add a DEFAULT to whine_queries stuff so that editwhines.cgi
+        # works on PostgreSQL.
+        $dbh->bz_alter_column('whine_queries', 'title', {TYPE => 'varchar(128)',
+                              NOTNULL => 1, DEFAULT => "''"});
+    }
+}
+
+sub _fix_attachments_submitter_id_idx {
+    my $dbh = Bugzilla->dbh;
+    # 2005-06-29 bugreport@peshkin.net, bug 299156
+    if ($dbh->bz_index_info('attachments', 'attachments_submitter_id_idx')
+        && (scalar(@{$dbh->bz_index_info('attachments',
+                                         'attachments_submitter_id_idx'
+                                        )->{FIELDS}}) < 2)) 
+    {
+        $dbh->bz_drop_index('attachments', 'attachments_submitter_id_idx');
+    }
+    $dbh->bz_add_index('attachments', 'attachments_submitter_id_idx',
+                       [qw(submitter_id bug_id)]);
+}
+
+sub _copy_attachments_thedata_to_attach_data {
+    my $dbh = Bugzilla->dbh;
+    # 2005-08-25 - bugreport@peshkin.net - Bug 305333
+    if ($dbh->bz_column_info("attachments", "thedata")) {
+        print "Migrating attachment data to its own table...\n";
+        print "(This may take a very long time)\n";
+        $dbh->do("INSERT INTO attach_data (id, thedata)
+                       SELECT attach_id, thedata FROM attachments");
+        $dbh->bz_drop_column("attachments", "thedata");
+    }
+}
+
+sub _fix_broken_all_closed_series {
+    my $dbh = Bugzilla->dbh;
+
+    # 2005-11-26 - wurblzap@gmail.com - Bug 300473
+    # Repair broken automatically generated series queries for non-open bugs.
+    my $broken_series_indicator =
+        'field0-0-0=resolution&type0-0-0=notequals&value0-0-0=---';
+    my $broken_nonopen_series =
+        $dbh->selectall_arrayref("SELECT series_id, query FROM series
+                                 WHERE query LIKE '$broken_series_indicator%'");
+    if (@$broken_nonopen_series) {
+        print 'Repairing broken series...';
+        my $sth_nuke =
+            $dbh->prepare('DELETE FROM series_data WHERE series_id = ?');
+        # This statement is used to repair a series by replacing the broken
+        # query with the correct one.
+        my $sth_repair =
+            $dbh->prepare('UPDATE series SET query = ? WHERE series_id = ?');
+        # The corresponding series for open bugs look like one of these two
+        # variations (bug 225687 changed the order of bug states).
+        # This depends on the set of bug states representing open bugs not
+        # to have changed since series creation.
+        my $open_bugs_query_base_old =
+            join("&", map { "bug_status=" . url_quote($_) }
+                          ('UNCONFIRMED', 'NEW', 'ASSIGNED', 'REOPENED'));
+        my $open_bugs_query_base_new =
+            join("&", map { "bug_status=" . url_quote($_) } BUG_STATE_OPEN);
+        my $sth_openbugs_series =
+            $dbh->prepare("SELECT series_id FROM series WHERE query IN (?, ?)");
+        # Statement to find the series which has collected the most data.
+        my $sth_data_collected =
+            $dbh->prepare('SELECT count(*) FROM series_data 
+                            WHERE series_id = ?');
+        # Statement to select a broken non-open bugs count data entry.
+        my $sth_select_broken_nonopen_data =
+            $dbh->prepare('SELECT series_date, series_value FROM series_data' .
+                          ' WHERE series_id = ?');
+        # Statement to select an open bugs count data entry.
+        my $sth_select_open_data =
+            $dbh->prepare('SELECT series_value FROM series_data' .
+                          ' WHERE series_id = ? AND series_date = ?');
+        # Statement to fix a broken non-open bugs count data entry.
+        my $sth_fix_broken_nonopen_data =
+            $dbh->prepare('UPDATE series_data SET series_value = ?' .
+                          ' WHERE series_id = ? AND series_date = ?');
+        # Statement to delete an unfixable broken non-open bugs count data 
+        # entry.
+        my $sth_delete_broken_nonopen_data =
+            $dbh->prepare('DELETE FROM series_data' .
+                          ' WHERE series_id = ? AND series_date = ?');
+        foreach (@$broken_nonopen_series) {
+            my ($broken_series_id, $nonopen_bugs_query) = @$_;
+
+            # Determine the product-and-component part of the query.
+            if ($nonopen_bugs_query =~ /^$broken_series_indicator(.*)$/) {
+                my $prodcomp = $1;
+
+                # If there is more than one series for the corresponding 
+                # open-bugs series, we pick the one with the most data,
+                # which should be the one which was generated on creation.
+                # It's a pity we can't do subselects.
+                $sth_openbugs_series->execute(
+                    $open_bugs_query_base_old . $prodcomp,
+                    $open_bugs_query_base_new . $prodcomp);
+
+                my ($found_open_series_id, $datacount) = (undef, -1);
+                foreach my $open_ser_id ($sth_openbugs_series->fetchrow_array) {
+                    $sth_data_collected->execute($open_ser_id);
+                    my ($this_datacount) = $sth_data_collected->fetchrow_array;
+                    if ($this_datacount > $datacount) {
+                        $datacount = $this_datacount;
+                        $found_open_series_id = $open_ser_id;
+                    }
+                }
+
+                if ($found_open_series_id) {
+                    # Move along corrupted series data and correct it. The
+                    # corruption consists of it being the number of all bugs
+                    # instead of the number of non-open bugs, so we calculate
+                    # the correct count by subtracting the number of open bugs.
+                    # If there is no corresponding open-bugs count for some
+                    # reason (shouldn't happen), we drop the data entry.
+                    print " $broken_series_id...";
+                    $sth_select_broken_nonopen_data->execute($broken_series_id);
+                    while (my $rowref =
+                           $sth_select_broken_nonopen_data->fetchrow_arrayref) 
+                    {
+                        my ($date, $broken_value) = @$rowref;
+                        my ($openbugs_value) =
+                            $dbh->selectrow_array($sth_select_open_data, undef,
+                                                  $found_open_series_id, $date);
+                        if (defined($openbugs_value)) {
+                            $sth_fix_broken_nonopen_data->execute
+                                ($broken_value - $openbugs_value,
+                                 $broken_series_id, $date);
+                        }
+                        else {
+                            print <<EOT;
+
+WARNING - During repairs of series $broken_series_id, the irreparable data
+entry for date $date was encountered and is being deleted.
+
+Continuing repairs...
+EOT
+                            $sth_delete_broken_nonopen_data->execute
+                                ($broken_series_id, $date);
+                        }
+                    }
+
+                    # Fix the broken query so that it collects correct data 
+                    # in the future.
+                    $nonopen_bugs_query =~
+                        s/^$broken_series_indicator/field0-0-0=resolution&type0-0-0=regexp&value0-0-0=./;
+                    $sth_repair->execute($nonopen_bugs_query, 
+                                         $broken_series_id);
+                }
+                else {
+                    print <<EOT;
+
+WARNING - Series $broken_series_id was meant to collect non-open bug 
+counts, but it has counted all bugs instead. It cannot be repaired
+automatically because no series that collected open bug counts was found.
+You'll probably want to delete or repair collected data for 
+series $broken_series_id manually
+
+Continuing repairs...
+EOT
+                } #  if ($found_open_series_id)
+            } #  if ($nonopen_bugs_query =~
+        } # foreach (@$broken_nonopen_series)
+        print " done.\n";
+    } # if (@$broken_nonopen_series)
+}
+
+sub _clean_control_characters_from_short_desc {
+    my $dbh = Bugzilla->dbh;
+
+    # Fixup for Bug 101380
+    # "Newlines, nulls, leading/trailing spaces are getting into summaries"
+
+    my $controlchar_bugs =
+        $dbh->selectall_arrayref("SELECT short_desc, bug_id FROM bugs WHERE " .
+            $dbh->sql_regexp('short_desc', "'[[:cntrl:]]'"));
+    if (scalar(@$controlchar_bugs)) {
+        my $msg = 'Cleaning control characters from bug summaries...';
+        my $found = 0;
+        foreach (@$controlchar_bugs) {
+            my ($short_desc, $bug_id) = @$_;
+            my $clean_short_desc = clean_text($short_desc);
+            if ($clean_short_desc ne $short_desc) {
+                print $msg if !$found;
+                $found = 1;
+                print " $bug_id...";
+                $dbh->do("UPDATE bugs SET short_desc = ? WHERE bug_id = ?",
+                          undef, $clean_short_desc, $bug_id);
+            }
+        }
+        print " done.\n" if $found;
+    }
+}
+
+sub _stop_storing_inactive_flags {
+    my $dbh = Bugzilla->dbh;
+    # 2006-03-02 LpSolit@gmail.com - Bug 322285
+    # Do not store inactive flags in the DB anymore.
+    if ($dbh->bz_column_info('flags', 'id')->{'TYPE'} eq 'INT3') {
+        # We first have to remove all existing inactive flags.
+        if ($dbh->bz_column_info('flags', 'is_active')) {
+            $dbh->do('DELETE FROM flags WHERE is_active = 0');
+        }
+
+       # Now we convert the id column to the auto_increment format.
+        $dbh->bz_alter_column('flags', 'id',
+           {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1});
+
+        # And finally, we remove the is_active column.
+        $dbh->bz_drop_column('flags', 'is_active');
+    }
+}
+
+sub _change_short_desc_from_mediumtext_to_varchar {
+    my $dbh = Bugzilla->dbh;
+    # short_desc should not be a mediumtext, fix anything longer than 255 chars.
+    if($dbh->bz_column_info('bugs', 'short_desc')->{TYPE} eq 'MEDIUMTEXT') {
+        # Move extremely long summaries into a comment ("from" the Reporter),
+        # and then truncate the summary.
+        my $long_summary_bugs = $dbh->selectall_arrayref(
+            'SELECT bug_id, short_desc, reporter
+               FROM bugs WHERE LENGTH(short_desc) > 255');
+
+        if (@$long_summary_bugs) {
+            print <<EOT;
+
+WARNING: Some of your bugs had summaries longer than 255 characters.
+They have had their original summary copied into a comment, and then
+the summary was truncated to 255 characters. The affected bug numbers were:
+EOT
+            my $comment_sth = $dbh->prepare(
+                'INSERT INTO longdescs (bug_id, who, thetext, bug_when)
+                      VALUES (?, ?, ?, NOW())');
+            my $desc_sth = $dbh->prepare('UPDATE bugs SET short_desc = ?
+                                           WHERE bug_id = ?');
+            my @affected_bugs;
+            foreach my $bug (@$long_summary_bugs) {
+                my ($bug_id, $summary, $reporter_id) = @$bug;
+                my $summary_comment = "The original summary for this bug"
+                   . " was longer than 255 characters, and so it was truncated"
+                   . " when Bugzilla was upgraded. The original summary was:"
+                   . "\n\n$summary";
+                $comment_sth->execute($bug_id, $reporter_id, $summary_comment);
+                my $short_summary = substr($summary, 0, 252) . "...";
+                $desc_sth->execute($short_summary, $bug_id);
+                push(@affected_bugs, $bug_id);
+            }
+            print join(', ', @affected_bugs) . "\n\n";
+        }
+
+        $dbh->bz_alter_column('bugs', 'short_desc', {TYPE => 'varchar(255)',
+                                                     NOTNULL => 1});
+    }
+}
+
+sub _move_namedqueries_linkinfooter_to_its_own_table {
+    my $dbh = Bugzilla->dbh;
+    if ($dbh->bz_column_info("namedqueries", "linkinfooter")) {
+        # Move link-in-footer information into a table of its own.
+        my $sth_read = $dbh->prepare('SELECT id, userid
+                                        FROM namedqueries
+                                       WHERE linkinfooter = 1');
+        my $sth_write = $dbh->prepare('INSERT INTO namedqueries_link_in_footer
+                                       (namedquery_id, user_id) VALUES (?, ?)');
+        $sth_read->execute();
+        while (my ($id, $userid) = $sth_read->fetchrow_array()) {
+            $sth_write->execute($id, $userid);
+        }
+        $dbh->bz_drop_column("namedqueries", "linkinfooter");
+    }
+}
+
+sub _add_classifications_sortkey {
+    my $dbh = Bugzilla->dbh;
+    # 2006-07-07 olav@bkor.dhs.org - Bug 277377
+    # Add a sortkey to the classifications
+    if (!$dbh->bz_column_info('classifications', 'sortkey')) {
+        $dbh->bz_add_column('classifications', 'sortkey',
+                            {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0});
+
+        my $class_ids = $dbh->selectcol_arrayref(
+            'SELECT id FROM classifications ORDER BY name');
+        my $sth = $dbh->prepare('UPDATE classifications SET sortkey = ? ' .
+                                 'WHERE id = ?');
+        my $sortkey = 0;
+        foreach my $class_id (@$class_ids) {
+            $sth->execute($sortkey, $class_id);
+            $sortkey += 100;
+        }
+    }
+}
+
+sub _move_data_nomail_into_db {
+    my $dbh = Bugzilla->dbh;
+    my $datadir = bz_locations()->{'datadir'};
+    # 2006-07-14 karl@kornel.name - Bug 100953
+    # If a nomail file exists, move its contents into the DB
+    $dbh->bz_add_column('profiles', 'disable_mail',
+        { TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE' });
+    if (-e "$datadir/nomail") {
+        # We have a data/nomail file, read it in and delete it
+        my %nomail;
+        print "Found a data/nomail file.  Moving nomail entries into DB...\n";
+        my $nomail_file = new IO::File("$datadir/nomail", 'r');
+        while (<$nomail_file>) {
+            $nomail{trim($_)} = 1;
+        }
+        $nomail_file->close;
+
+        # Go through each entry read.  If a user exists, set disable_mail.
+        my $query = $dbh->prepare('UPDATE profiles
+                                      SET disable_mail = 1
+                                    WHERE userid = ?');
+        foreach my $user_to_check (keys %nomail) {
+            my $uid;
+            if ($uid = Bugzilla::User::login_to_id($user_to_check)) {
+                my $user = new Bugzilla::User($uid);
+                print "\tDisabling email for user ", $user->email, "\n";
+                $query->execute($user->id);
+                delete $nomail{$user->email};
+            }
+        }
+
+        # If there are any nomail entries remaining, move them to nomail.bad
+        # and say something to the user.
+        if (scalar(keys %nomail)) {
+            print <<EOT;
+
+WARNING: The following users were listed in data/nomail, but do not
+have an account here. The unmatched entries have been moved
+to $datadir/nomail.bad:
+EOT
+            my $nomail_bad = new IO::File("$datadir/nomail.bad", '>>');
+            foreach my $unknown_user (keys %nomail) {
+                print "\t$unknown_user\n";
+                print $nomail_bad "$unknown_user\n";
+                delete $nomail{$unknown_user};
+            }
+            $nomail_bad->close;
+            print "\n";
+        }
+
+        # Now that we don't need it, get rid of the nomail file.
+        unlink "$datadir/nomail";
+    }
+}
+
 1;
 
 __END__
@@ -2158,17 +2660,54 @@ Bugzilla::Install::DB - Fix up the database during installation.
 
 =head1 SYNOPSIS
 
+ use Bugzilla::Install::DB qw(indicate_progress);
+ Bugzilla::Install::DB::update_table_definitions();
+
+ indicate_progress({ total => $total, current => $count, every => 10 });
+
 =head1 DESCRIPTION
 
 This module is used primarily by L<checksetup.pl> to modify the 
 database during upgrades.
 
+=head1 SUBROUTINES
+
 =over
 
-=back
+=item C<update_table_definitions()>
 
-=head1 SUBROUTINES
+Description: This is the primary code that updates table definitions
+             during upgrades. If you modify the schema in some 
+             way, you should add code to the end of this function to 
+             make sure that your modifications happen over all installations.
 
-=over
+Params:      none
+
+Returns:     nothing
+
+=item C<update_fielddefs_definition()>
+
+Description: L<checksetup.pl> depends on the fielddefs table having
+             its schema adjusted before the rest of the tables. So
+             these schema updates happen in a separate function from
+             L</update_table_definitions()>.
+
+Params:      none
+
+Returns:     nothing
+
+=item C<indicate_progress({ total => $total, current => $count, every => 1 })>
+
+Description: This prints out lines of dots as a long update is going on,
+             to let the user know where we are and that we're not frozen.
+             A new line of dots will start every 60 dots.
+
+Params:      C<total> - The total number of items we're processing.
+             C<current> - The number of the current item we're processing.
+             C<every> - How often the function should print out a dot.
+               For example, if this is 10, the function will print out
+               a dot every ten items.
+
+Returns:     nothing
 
 =back
index d408a70e740957fe1611ef0ab7d28139dcb7559d..f9a5a4083776e1eea246b18c3ddd4e3c18fac18a 100644 (file)
@@ -348,6 +348,11 @@ EOT
         rmtree("shadow");
     }
 
+    if (-e "$datadir/versioncache") {
+        print "Removing versioncache...\n";
+        unlink "$datadir/versioncache";
+    }
+
 }
 
 sub create_htaccess {
index ae3cda5e56a1b9cf21678243937882c8acf916c5..15db11053c6126df8a8be3ae1ab1438621b5c006 100755 (executable)
@@ -172,6 +172,19 @@ Note: sometimes those special comments occur more than once. For
 example, C<--LOCAL--> is used at least 3 times in this code!  C<--TABLE-->
 is also used more than once, so search for each and every occurrence!
 
+=head2 Modifying the Database
+
+Sometimes you'll want to modify the database. In fact, that's mostly
+what checksetup does, is upgrade old Bugzilla databases to the modern
+format.
+
+If you'd like to know how to make changes to the datbase, see
+the information in the Bugzilla Developer's Guide, at:
+L<http:E<sol>E<sol>www.bugzilla.orgE<sol>docsE<sol>developer.html#sql-schema>
+
+Also see L<Bugzilla::DB/"Schema Modification Methods"> and 
+L<Bugzilla::DB/"Schema Information Methods">.
+
 =head1 RUNNING CHECKSETUP NON-INTERACTIVELY
 
 To operate checksetup non-interactively, run it with a single argument
@@ -203,14 +216,12 @@ function calls needs to be specified in this file.
 
 =head1 SEE ALSO
 
-L<Bugzilla::Install::Requirements>
-
-L<Bugzilla::Install::Localconfig>
-
-L<Bugzilla::Install::Filesystem>
-
-L<Bugzilla::Config/update_params>
-
+L<Bugzilla::Install::Requirements>,
+L<Bugzilla::Install::Localconfig>,
+L<Bugzilla::Install::Filesystem>,
+L<Bugzilla::Install::DB>,
+L<Bugzilla::Install>,
+L<Bugzilla::Config/update_params>, and
 L<Bugzilla::DB/CONNECTION>
 
 =cut
@@ -516,54 +527,7 @@ use constant OLD_FIELD_DEFS => (
 # Calling Bugzilla::Field::create_or_update depends on the
 # fielddefs table having a modern definition. So, we have to make
 # these particular schema changes before we make any other schema changes.
-
-# 2005-02-21 - LpSolit@gmail.com - Bug 279910
-# qacontact_accessible and assignee_accessible field names no longer exist
-# in the 'bugs' table. Their corresponding entries in the 'bugs_activity'
-# table should therefore be marked as obsolete, meaning that they cannot
-# be used anymore when querying the database - they are not deleted in
-# order to keep track of these fields in the activity table.
-if (!$dbh->bz_column_info('fielddefs', 'obsolete')) {
-    $dbh->bz_add_column('fielddefs', 'obsolete',
-        {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'});
-    print "Marking qacontact_accessible and assignee_accessible as obsolete",
-          " fields...\n";
-    $dbh->do("UPDATE fielddefs SET obsolete = 1
-              WHERE name = 'qacontact_accessible'
-                 OR name = 'assignee_accessible'");
-}
-
-# 2005-08-10 Myk Melez <myk@mozilla.org> bug 287325
-# Record each field's type and whether or not it's a custom field in fielddefs.
-$dbh->bz_add_column('fielddefs', 'type',
-                    { TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0 });
-$dbh->bz_add_column('fielddefs', 'custom',
-                    { TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE' });
-
-$dbh->bz_add_column('fielddefs', 'enter_bug',
-    {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE'});
-
-# Change the name of the fieldid column to id, so that fielddefs
-# can use Bugzilla::Object easily. We have to do this up here, because
-# otherwise adding these field definitions will fail.
-$dbh->bz_rename_column('fielddefs', 'fieldid', 'id');
-
-# If the largest fielddefs sortkey is less than 100, then
-# we're using the old sorting system, and we should convert
-# it to the new one before adding any new definitions.
-if (!$dbh->selectrow_arrayref(
-        'SELECT COUNT(id) FROM fielddefs WHERE sortkey >= 100'))
-{
-    print "Updating the sortkeys for the fielddefs table...\n";
-    my $field_ids = $dbh->selectcol_arrayref(
-        'SELECT id FROM fielddefs ORDER BY sortkey');
-    my $sortkey = 100;
-    foreach my $field_id (@$field_ids) {
-        $dbh->do('UPDATE fielddefs SET sortkey = ? WHERE id = ?',
-                 undef, $sortkey, $field_id);
-        $sortkey += 100;
-    }
-}
+Bugzilla::Install::DB::update_fielddefs_definition();
 
 # Create field definitions
 foreach my $definition (OLD_FIELD_DEFS) {
@@ -629,15 +593,12 @@ if ($old_field_id && ($old_field_name ne $new_field_name)) {
         $query =~ s/=\Q$old_field_name\E(&|$)/=$new_field_name$1/gi;
         $sth_UpdateSeries->execute($query, $series_id);
     }
-
     # Now that saved searches have been fixed, we can fix the field name.
     print "Fixing the 'fielddefs' table...\n";
     print "New field name: " . $new_field_name . "\n";
     $dbh->do('UPDATE fielddefs SET name = ? WHERE id = ?',
               undef, ($new_field_name, $old_field_id));
 }
-
-
 Bugzilla::Field::create_or_update(
     {name => $new_field_name, desc => $field_description});
 
@@ -689,421 +650,11 @@ if (!$class_count) {
 }
 
 ###########################################################################
-# Update the tables to the current definition  --TABLE--
+# Update the tables to the current definition --TABLE--
 ###########################################################################
 
 Bugzilla::Install::DB::update_table_definitions();        
 
-# 2005-04-07 - alt@sonic.net, bug 289455
-# make classification_id field type be consistent with DB:Schema
-$dbh->bz_alter_column('products', 'classification_id',
-                      {TYPE => 'INT2', NOTNULL => 1, DEFAULT => '1'});
-
-# initialowner was accidentally NULL when we checked-in Schema,
-# when it really should be NOT NULL.
-$dbh->bz_alter_column('components', 'initialowner',
-                      {TYPE => 'INT3', NOTNULL => 1}, 0);
-
-# 2005-03-28 - bug 238800 - index flags.type_id to make editflagtypes.cgi speedy
-$dbh->bz_add_index('flags', 'flags_type_id_idx', [qw(type_id)]);
-
-# For a short time, the flags_type_id_idx was misnamed in upgraded installs.
-$dbh->bz_drop_index('flags', 'type_id');
-
-# 2005-04-28 - LpSolit@gmail.com - Bug 7233: add an index to versions
-$dbh->bz_alter_column('versions', 'value',
-                      {TYPE => 'varchar(64)', NOTNULL => 1});
-$dbh->bz_add_index('versions', 'versions_product_id_idx',
-                   {TYPE => 'UNIQUE', FIELDS => [qw(product_id value)]});
-
-# Milestone sortkeys get a default just like all other sortkeys.
-if (!exists $dbh->bz_column_info('milestones', 'sortkey')->{DEFAULT}) {
-    $dbh->bz_alter_column('milestones', 'sortkey', 
-                          {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0});
-}
-
-# 2005-06-14 - LpSolit@gmail.com - Bug 292544: only set creation_ts
-# when all bug fields have been correctly set.
-$dbh->bz_alter_column('bugs', 'creation_ts', {TYPE => 'DATETIME'});
-
-if (!exists $dbh->bz_column_info('whine_queries', 'title')->{DEFAULT}) {
-
-    # The below change actually has nothing to do with the whine_queries
-    # change, it just has to be contained within a schema change so that
-    # it doesn't run every time we run checksetup.
-
-    # Old Bugzillas have "other" as an OS choice, new ones have "Other"
-    # (capital O).
-    print "Setting any 'other' op_sys to 'Other'...\n";
-    $dbh->do('UPDATE op_sys SET value = ? WHERE value = ?',
-             undef, "Other", "other");
-    $dbh->do('UPDATE bugs SET op_sys = ? WHERE op_sys = ?',
-             undef, "Other", "other");
-    if (Bugzilla->params->{'defaultopsys'} eq 'other') {
-        # We can't actually fix the param here, because WriteParams() will
-        # make $datadir/params unwriteable to the webservergroup.
-        # It's too much of an ugly hack to copy the permission-fixing code
-        # down to here. (It would create more potential future bugs than
-        # it would solve problems.)
-        print "WARNING: Your 'defaultopsys' param is set to 'other', but"
-            . " Bugzilla now\n"
-            . "         uses 'Other' (capital O).\n";
-    }
-
-    # Add a DEFAULT to whine_queries stuff so that editwhines.cgi
-    # works on PostgreSQL.
-    $dbh->bz_alter_column('whine_queries', 'title', {TYPE => 'varchar(128)', 
-                          NOTNULL => 1, DEFAULT => "''"});
-}
-
-# 2005-06-29 bugreport@peshkin.net, bug 299156
-if ($dbh->bz_index_info('attachments', 'attachments_submitter_id_idx')
-   && (scalar(@{$dbh->bz_index_info('attachments',
-                                    'attachments_submitter_id_idx'
-                                   )->{FIELDS}}) < 2)
-      ) {
-    $dbh->bz_drop_index('attachments', 'attachments_submitter_id_idx');
-}
-$dbh->bz_add_index('attachments', 'attachments_submitter_id_idx',
-                   [qw(submitter_id bug_id)]);
-
-# 2005-08-25 - bugreport@peshkin.net - Bug 305333
-if ($dbh->bz_column_info("attachments", "thedata")) {
-    print "Migrating attachment data to its own table...\n";
-    print "(This may take a very long time)\n";
-    $dbh->do("INSERT INTO attach_data (id, thedata) 
-                   SELECT attach_id, thedata FROM attachments");
-    $dbh->bz_drop_column("attachments", "thedata");    
-}
-
-# 2005-11-26 - wurblzap@gmail.com - Bug 300473
-# Repair broken automatically generated series queries for non-open bugs.
-my $broken_series_indicator =
-    'field0-0-0=resolution&type0-0-0=notequals&value0-0-0=---';
-my $broken_nonopen_series =
-    $dbh->selectall_arrayref("SELECT series_id, query FROM series
-                               WHERE query LIKE '$broken_series_indicator%'");
-if (@$broken_nonopen_series) {
-    print 'Repairing broken series...';
-    my $sth_nuke =
-        $dbh->prepare('DELETE FROM series_data WHERE series_id = ?');
-    # This statement is used to repair a series by replacing the broken query
-    # with the correct one.
-    my $sth_repair =
-        $dbh->prepare('UPDATE series SET query = ? WHERE series_id = ?');
-    # The corresponding series for open bugs look like one of these two
-    # variations (bug 225687 changed the order of bug states).
-    # This depends on the set of bug states representing open bugs not to have
-    # changed since series creation.
-    my $open_bugs_query_base_old = 
-        join("&", map { "bug_status=" . url_quote($_) }
-                      ('UNCONFIRMED', 'NEW', 'ASSIGNED', 'REOPENED'));
-    my $open_bugs_query_base_new = 
-        join("&", map { "bug_status=" . url_quote($_) } BUG_STATE_OPEN);
-    my $sth_openbugs_series =
-        $dbh->prepare("SELECT series_id FROM series
-                        WHERE query IN (?, ?)");
-    # Statement to find the series which has collected the most data.
-    my $sth_data_collected =
-        $dbh->prepare('SELECT count(*) FROM series_data WHERE series_id = ?');
-    # Statement to select a broken non-open bugs count data entry.
-    my $sth_select_broken_nonopen_data =
-        $dbh->prepare('SELECT series_date, series_value FROM series_data' .
-                      ' WHERE series_id = ?');
-    # Statement to select an open bugs count data entry.
-    my $sth_select_open_data =
-        $dbh->prepare('SELECT series_value FROM series_data' .
-                      ' WHERE series_id = ? AND series_date = ?');
-    # Statement to fix a broken non-open bugs count data entry.
-    my $sth_fix_broken_nonopen_data =
-        $dbh->prepare('UPDATE series_data SET series_value = ?' .
-                      ' WHERE series_id = ? AND series_date = ?');
-    # Statement to delete an unfixable broken non-open bugs count data entry.
-    my $sth_delete_broken_nonopen_data =
-        $dbh->prepare('DELETE FROM series_data' .
-                      ' WHERE series_id = ? AND series_date = ?');
-
-    foreach (@$broken_nonopen_series) {
-        my ($broken_series_id, $nonopen_bugs_query) = @$_;
-
-        # Determine the product-and-component part of the query.
-        if ($nonopen_bugs_query =~ /^$broken_series_indicator(.*)$/) {
-            my $prodcomp = $1;
-
-            # If there is more than one series for the corresponding open-bugs
-            # series, we pick the one with the most data, which should be the
-            # one which was generated on creation.
-            # It's a pity we can't do subselects.
-            $sth_openbugs_series->execute($open_bugs_query_base_old . $prodcomp,
-                                          $open_bugs_query_base_new . $prodcomp);
-            my ($found_open_series_id, $datacount) = (undef, -1);
-            foreach my $open_series_id ($sth_openbugs_series->fetchrow_array()) {
-                $sth_data_collected->execute($open_series_id);
-                my ($this_datacount) = $sth_data_collected->fetchrow_array();
-                if ($this_datacount > $datacount) {
-                    $datacount = $this_datacount;
-                    $found_open_series_id = $open_series_id;
-                }
-            }
-
-            if ($found_open_series_id) {
-                # Move along corrupted series data and correct it. The
-                # corruption consists of it being the number of all bugs
-                # instead of the number of non-open bugs, so we calculate the
-                # correct count by subtracting the number of open bugs.
-                # If there is no corresponding open-bugs count for some reason
-                # (shouldn't happen), we drop the data entry.
-                print " $broken_series_id...";
-                $sth_select_broken_nonopen_data->execute($broken_series_id);
-                while (my $rowref =
-                       $sth_select_broken_nonopen_data->fetchrow_arrayref()) {
-                    my ($date, $broken_value) = @$rowref;
-                    my ($openbugs_value) =
-                        $dbh->selectrow_array($sth_select_open_data, undef,
-                                              $found_open_series_id, $date);
-                    if (defined($openbugs_value)) {
-                        $sth_fix_broken_nonopen_data->execute
-                            ($broken_value - $openbugs_value,
-                             $broken_series_id, $date);
-                    }
-                    else {
-                        print "\nWARNING - During repairs of series " .
-                              "$broken_series_id, the irreparable data\n" .
-                              "entry for date $date was encountered and is " .
-                              "being deleted.\n" .
-                              "Continuing repairs...";
-                        $sth_delete_broken_nonopen_data->execute
-                            ($broken_series_id, $date);
-                    }
-                }
-
-                # Fix the broken query so that it collects correct data in the
-                # future.
-                $nonopen_bugs_query =~
-                    s/^$broken_series_indicator/field0-0-0=resolution&type0-0-0=regexp&value0-0-0=./;
-                $sth_repair->execute($nonopen_bugs_query, $broken_series_id);
-            }
-            else {
-                print "\nWARNING - Series $broken_series_id was meant to\n" .
-                      "collect non-open bug counts, but it has counted\n" .
-                      "all bugs instead. It cannot be repaired\n" .
-                      "automatically because no series that collected open\n" .
-                      "bug counts was found. You'll probably want to delete\n" .
-                      "or repair collected data for series $broken_series_id " .
-                      "manually.\n" .
-                      "Continuing repairs...";
-            }
-        }
-    }
-    print " done.\n";
-}
-
-# 2005-09-15 lance.larsh@oracle.com Bug 308717
-if ($dbh->bz_column_info("series", "public")) {
-    # PUBLIC is a reserved word in Oracle, so renaming the column
-    # PUBLIC in table SERIES avoids having to quote the column name
-    # in every query against that table
-    $dbh->bz_rename_column('series', 'public', 'is_public');
-}
-
-# 2005-09-28 bugreport@peshkin.net Bug 149504
-$dbh->bz_add_column('attachments', 'isurl',
-                    {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0});
-
-# 2005-10-21 LpSolit@gmail.com - Bug 313020
-$dbh->bz_add_column('namedqueries', 'query_type',
-                    {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0});
-
-# 2005-11-04 LpSolit@gmail.com - Bug 305927
-$dbh->bz_alter_column('groups', 'userregexp', 
-                      {TYPE => 'TINYTEXT', NOTNULL => 1, DEFAULT => "''"});
-
-# 2005-09-26 - olav@bkor.dhs.org - Bug 119524
-# Convert logincookies into a varchar
-# this allows to store a random token instead of a guessable auto_increment
-$dbh->bz_alter_column('logincookies', 'cookie',
-                      {TYPE => 'varchar(16)', PRIMARYKEY => 1, NOTNULL => 1});
-
-# Fixup for Bug 101380
-# "Newlines, nulls, leading/trailing spaces are getting into summaries"
-
-my $controlchar_bugs =
-    $dbh->selectall_arrayref("SELECT short_desc, bug_id FROM bugs WHERE " .
-                             $dbh->sql_regexp('short_desc', "'[[:cntrl:]]'"));
-if (scalar(@$controlchar_bugs))
-{
-    my $msg = 'Cleaning control characters from bug summaries...';
-    my $found = 0;
-    foreach (@$controlchar_bugs) {
-        my ($short_desc, $bug_id) = @$_;
-        my $clean_short_desc = clean_text($short_desc);
-        if ($clean_short_desc ne $short_desc) {
-            print $msg if !$found;
-            $found = 1;
-            print " $bug_id...";
-            $dbh->do("UPDATE bugs SET short_desc = ? WHERE bug_id = ?",
-                      undef, $clean_short_desc, $bug_id);
-        }
-    }
-    print " done.\n" if $found;
-}
-
-# 2005-12-07 altlst@sonic.net -- Bug 225221
-$dbh->bz_add_column('longdescs', 'comment_id',
-                    {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1});
-
-# 2006-03-02 LpSolit@gmail.com - Bug 322285
-# Do not store inactive flags in the DB anymore.
-if ($dbh->bz_column_info('flags', 'id')->{'TYPE'} eq 'INT3') {
-    # We first have to remove all existing inactive flags.
-    if ($dbh->bz_column_info('flags', 'is_active')) {
-        $dbh->do('DELETE FROM flags WHERE is_active = 0');
-    }
-
-    # Now we convert the id column to the auto_increment format.
-    $dbh->bz_alter_column('flags', 'id',
-                          {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1});
-
-    # And finally, we remove the is_active column.
-    $dbh->bz_drop_column('flags', 'is_active');
-}
-
-# short_desc should not be a mediumtext, fix anything longer than 255 chars.
-if($dbh->bz_column_info('bugs', 'short_desc')->{TYPE} eq 'MEDIUMTEXT') {
-    # Move extremely long summaries into a comment ("from" the Reporter),
-    # and then truncate the summary.
-    my $long_summary_bugs = $dbh->selectall_arrayref(
-        'SELECT bug_id, short_desc, reporter
-           FROM bugs WHERE LENGTH(short_desc) > 255');
-
-    if (@$long_summary_bugs) {
-        print <<EOF;
-
-WARNING: Some of your bugs had summaries longer than 255 characters.
-They have had their original summary copied into a comment, and then
-the summary was truncated to 255 characters. The affected bug numbers were:
-EOF
-        my $comment_sth = $dbh->prepare(
-            'INSERT INTO longdescs (bug_id, who, thetext, bug_when) 
-                  VALUES (?, ?, ?, NOW())');
-        my $desc_sth = $dbh->prepare('UPDATE bugs SET short_desc = ? 
-                                       WHERE bug_id = ?');
-        my @affected_bugs;
-        foreach my $bug (@$long_summary_bugs) {
-            my ($bug_id, $summary, $reporter_id) = @$bug;
-            my $summary_comment = "The original summary for this bug"
-               . " was longer than 255 characters, and so it was truncated"
-               . " when Bugzilla was upgraded. The original summary was:"
-               . "\n\n$summary";
-            $comment_sth->execute($bug_id, $reporter_id, $summary_comment);
-            my $short_summary = substr($summary, 0, 252) . "...";
-            $desc_sth->execute($short_summary, $bug_id);
-            push(@affected_bugs, $bug_id);
-        }
-        print join(', ', @affected_bugs) . "\n\n";
-    }
-
-    $dbh->bz_alter_column('bugs', 'short_desc', {TYPE => 'varchar(255)', 
-                                                 NOTNULL => 1});
-}
-
-if (-e "$datadir/versioncache") {
-    print "Removing versioncache...\n";
-    unlink "$datadir/versioncache";
-}
-
-# 2006-07-01 wurblzap@gmail.com -- Bug 69000
-$dbh->bz_add_column('namedqueries', 'id',
-                    {TYPE => 'MEDIUMSERIAL', NOTNULL => 1, PRIMARYKEY => 1});
-if ($dbh->bz_column_info("namedqueries", "linkinfooter")) {
-    # Move link-in-footer information into a table of its own.
-    my $sth_read = $dbh->prepare('SELECT id, userid
-                                    FROM namedqueries 
-                                   WHERE linkinfooter = 1');
-    my $sth_write = $dbh->prepare('INSERT INTO namedqueries_link_in_footer
-                                   (namedquery_id, user_id) VALUES (?, ?)');
-    $sth_read->execute();
-    while (my ($id, $userid) = $sth_read->fetchrow_array()) {
-        $sth_write->execute($id, $userid);
-    }
-    $dbh->bz_drop_column("namedqueries", "linkinfooter");    
-}
-
-# 2006-07-07 olav@bkor.dhs.org - Bug 277377
-# Add a sortkey to the classifications
-if (!$dbh->bz_column_info('classifications', 'sortkey')) {
-    $dbh->bz_add_column('classifications', 'sortkey',
-                        {TYPE => 'INT2', NOTNULL => 1, DEFAULT => 0});
-
-    my $class_ids = $dbh->selectcol_arrayref('SELECT id FROM classifications ' .
-                                             'ORDER BY name');
-    my $sth = $dbh->prepare('UPDATE classifications SET sortkey = ? ' .
-                            'WHERE id = ?');
-    my $sortkey = 0;
-    foreach my $class_id (@$class_ids) {
-        $sth->execute($sortkey, $class_id);
-        $sortkey += 100;
-    }
-}
-
-# 2006-07-14 karl@kornel.name - Bug 100953
-# If a nomail file exists, move its contents into the DB
-$dbh->bz_add_column('profiles', 'disable_mail',
-                    { TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 'FALSE' });
-if (-e "$datadir/nomail") {
-    # We have a data/nomail file, read it in and delete it
-    my %nomail;
-    print "Found a data/nomail file.  Moving nomail entries into DB...\n";
-    open NOMAIL, '<', "$datadir/nomail";
-    while (<NOMAIL>) {
-        $nomail{trim($_)} = 1;
-    }
-    close NOMAIL;
-
-    # Go through each entry read.  If a user exists, set disable_mail.
-    my $query = $dbh->prepare('UPDATE profiles
-                                  SET disable_mail = 1
-                                WHERE userid = ?');
-    foreach my $user_to_check (keys %nomail) {
-        my $uid;
-        if ($uid = Bugzilla::User::login_to_id($user_to_check)) {
-            my $user = new Bugzilla::User($uid);
-            print "\tDisabling email for user ", $user->email, "\n";
-            $query->execute($user->id);
-            delete $nomail{$user->email};
-        }
-    }
-
-    # If there are any nomail entries remaining, move them to nomail.bad
-    # and say something to the user.
-    if (scalar(keys %nomail)) {
-        print 'The following users were listed in data/nomail, but do not ' .
-              'have an account here.  The unmatched entries have been moved ' .
-              "to $datadir/nomail.bad\n";
-        open NOMAIL_BAD, '>>', "$datadir/nomail.bad";
-        foreach my $unknown_user (keys %nomail) {
-            print "\t$unknown_user\n";
-            print NOMAIL_BAD "$unknown_user\n";
-            delete $nomail{$unknown_user};
-        }
-        close NOMAIL_BAD;
-    }
-
-    # Now that we don't need it, get rid of the nomail file.
-    unlink "$datadir/nomail";
-}
-
-
-# If you had to change the --TABLE-- definition in any way, then add your
-# differential change code *** A B O V E *** this comment.
-#
-# That is: if you add a new field, you first search for the first occurrence
-# of --TABLE-- and add your field to into the table hash. This new setting
-# would be honored for every new installation. Then add your
-# bz_add_field/bz_drop_field/bz_change_field_type/bz_rename_field code above.
-# This would then be honored by everyone who updates his Bugzilla installation.
-#
-
 #
 # Bugzilla uses --GROUPS-- to assign various rights to its users.
 #