use strict; use warnings; # groups table { foreach my $name ( qw(Groups1 Groups2 Groups3) ) { my ($status, $msg) = $RT::Handle->DropIndexIfExists( Table => 'Groups', Name => $name, ); my $method = $status ? 'debug' : 'warning'; RT->Logger->$method($msg); } my ($name, $msg) = $RT::Handle->CreateIndex( Table => 'Groups', Columns => [qw(Domain Type Instance)], CaseInsensitive => { domain => 1, type => 1 }, ); my $method = $name ? 'debug' : 'warning'; RT->Logger->$method($msg); ($name, $msg) = $RT::Handle->CreateIndex( Table => 'Groups', Columns => [qw(Domain Name Instance)], CaseInsensitive => { domain => 1, name => 1 }, ); $method = $name ? 'debug' : 'warning'; RT->Logger->$method($msg); ($name, $msg) = $RT::Handle->CreateIndex( Table => 'Groups', Columns => [qw(Instance)], ); $method = $name ? 'debug' : 'warning'; RT->Logger->$method($msg); } my $dedup = sub { my ($table, $column) = (@_); my $collection_class = "RT::$table"; my $record_class = $collection_class; $record_class =~ s/s$//; my $sql; my $cs = $RT::Handle->CaseSensitive; if ($cs) { $sql = "SELECT DISTINCT LOWER(t1.$column) FROM $table t1, $table t2" ." WHERE LOWER(t1.$column) = LOWER(t2.$column)" .' AND t1.id != t2.id'; } else { $sql = "SELECT DISTINCT t1.$column FROM $table t1, $table t2" ." WHERE t1.$column = t2.$column" .' AND t1.id != t2.id'; } my $dbh = $RT::Handle->dbh; my $sth = $dbh->prepare($sql); $sth->execute; my $found = 0; while ( my ($value) = $sth->fetchrow_array ) { $found = 1; my $ids = $dbh->selectcol_arrayref( "SELECT id FROM $table WHERE ". ($cs? "LOWER($column)" : $column) ." = LOWER(?)", undef, $value ); # skip first shift @$ids; foreach my $id ( @$ids ) { RT->Logger->debug("Changing $column of $record_class #". $id ); $dbh->do("UPDATE $table SET $column = ? WHERE id = ?", undef, $value . '-dup-'.$id, $id); } } if ( $found ) { RT->Logger->warning( "Records in $table table had non-unique values in $column column." ." $column has been changed for such records, and now matches '%-dup-%'" ); } }; # a few case insensitive and unique indexes { my @list = ( { Table => 'Queues', Column => 'Name' }, { Table => 'Users', Column => 'Name' }, ); foreach my $e (@list) { RT->Logger->debug("Checking index on ". $e->{'Column'} ." in ". $e->{'Table'} ); my (@indexes) = $RT::Handle->IndexesThatBeginWith( Table => $e->{'Table'}, Columns => [$e->{'Column'}] ); @indexes = grep {@{$_->{'Columns'}} == 1} @indexes; if (grep {$_->{Unique} && ($RT::Handle->CaseSensitive? $_->{'CaseInsensitive'}{ lc $e->{'Column'} } : 1 ) } @indexes ) { RT->Logger->debug("Required index exists. Skipping."); next; } $dedup->( $e->{'Table'}, $e->{'Column'} ); for my $index ( @indexes ) { my ($status, $msg) = $RT::Handle->DropIndex( Table => $e->{'Table'}, Name => $index->{'Name'}, ); my $method = $status ? 'debug' : 'warning'; RT->Logger->$method($msg); } my ($status, $msg) = $RT::Handle->CreateIndex( Table => $e->{'Table'}, Columns => [$e->{'Column'}], Unique => 1, CaseInsensitive => { lc $e->{'Column'} => 1 }, ); my $method = $status ? 'debug' : 'warning'; RT->Logger->$method($msg); } } # cached group members { $RT::Handle->MakeSureIndexExists( Table => 'CachedGroupMembers', Columns => ['MemberId', 'ImmediateParentId'], ); $RT::Handle->MakeSureIndexExists( Table => 'CachedGroupMembers', Columns => ['MemberId', 'GroupId'], Optional => ['Disabled'], ); $RT::Handle->DropIndexesThatArePrefix( Table => 'CachedGroupMembers', Columns => ['MemberId', 'GroupId', 'Disabled'], ); $RT::Handle->MakeSureIndexExists( Table => 'CachedGroupMembers', Columns => ['GroupId', 'MemberId'], Optional => ['Disabled'], ); $RT::Handle->DropIndexesThatArePrefix( Table => 'CachedGroupMembers', Columns => ['GroupId', 'MemberId', 'Disabled'], ); } # drop indexes that start with 'id' column foreach my $table ('Users', 'Tickets') { my @list = $RT::Handle->IndexesThatBeginWith( Table => $table, Columns => ['id'], ); @list = grep @{ $_->{'Columns'} } > 1, @list; foreach my $index (@list) { my ($status, $msg) = $RT::Handle->DropIndex( Table => $table, Name => $index->{'Name'}, ); my $method = $status ? 'debug' : 'warning'; RT->Logger->$method($msg); } } 1;