diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index f28329712..2635ae305 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -3,6 +3,8 @@ - fixed: EMS not displaying all users with a badge - fixed: WebGUI::Search - joinClass not documented - fixed: thingy's checkbox field + - Inbox and ?op=viewInbox can now handle millions of rows without taking 10 minutes to return + some results 7.5.18 - fixed: Collateral Image Manager broken in Firefox 3 diff --git a/docs/upgrades/upgrade_7.5.18-7.5.19.pl b/docs/upgrades/upgrade_7.5.18-7.5.19.pl index 67461738f..f53d92e7a 100644 --- a/docs/upgrades/upgrade_7.5.18-7.5.19.pl +++ b/docs/upgrades/upgrade_7.5.18-7.5.19.pl @@ -29,6 +29,7 @@ my $quiet; # this line required my $session = start(); # this line required # upgrade functions go here +addNewInboxIndexes( $session ); finish($session); # this line required @@ -42,6 +43,24 @@ finish($session); # this line required # print "DONE!\n" unless $quiet; #} +#---------------------------------------------------------------------------- +# Add new indexes to the inbox to make millions of messages possible +sub addNewInboxIndexes { + my $session = shift; + print "\tAdding new indexes to inbox. This may take a while... " unless $quiet; + + print "\n\t\tIndex on userId..." unless $quiet; + $session->db->write( + "CREATE INDEX pb_userId ON inbox ( userId )" + ); + + print "\n\t\tIndex on groupId..." unless $quiet; + $session->db->write( + "CREATE INDEX pb_groupId ON inbox ( groupId )" + ); + + print "\n\t\tDONE!\n" unless $quiet; +} # -------------- DO NOT EDIT BELOW THIS LINE -------------------------------- diff --git a/lib/WebGUI/Inbox.pm b/lib/WebGUI/Inbox.pm index bd35082d5..852534dc1 100644 --- a/lib/WebGUI/Inbox.pm +++ b/lib/WebGUI/Inbox.pm @@ -128,32 +128,64 @@ An integer indicating the number of messages to fetch. Defaults to 50. =cut sub getMessagesForUser { - my $self = shift; - my $user = shift; - my $limit = shift || 50; - my $page = shift || 1; - my $sortBy = shift; + my $self = shift; + my $user = shift; + my $perpage = shift || 50; + my $page = shift || 1; + my $sortBy = shift; - my @messages = (); - my $counter = 0; - - unless($sortBy eq "subject" || $sortBy eq "sentBy" || $sortBy eq "dateStamp") { - $sortBy = "status='pending' desc, dateStamp desc"; + my @messages = (); + my $counter = 0; + + my ( $sql, @bindvars ); + my $start = (($page-1) * $perpage); + my $end = $start + $page * $perpage; + my $limit = "$start, $perpage"; + + ### Here we're going to get enough rows to fill our needs ($end) from each subquery, then + ### use the UNION to grab only the rows we want to display ($limit) + + # If we have a way to sort, use that + if ( grep { $_ eq $sortBy } qw( subject sentBy dateStamp ) ) { + $sql = q{ ( SELECT messageId, userId, groupId, %s FROM inbox WHERE userId = "%s" ORDER BY %s LIMIT %s ) } + . q{ UNION } + . q{ ( SELECT messageId, userId, groupId, %s FROM inbox WHERE groupId IN ( %s ) ORDER BY %s LIMIT %s ) } + . q{ ORDER BY %s LIMIT %s } + ; + @bindvars = ( + $sortBy, $user->userId, $sortBy, $end, + $sortBy, $self->session->db->quoteAndJoin( $user->getGroupIdsRecursive ), $sortBy, $end, + $sortBy, $limit + ); } - - my $start = (($page-1) * $limit) + 1; - my $end = $page * $limit; - my $rs = $self->session->db->read("select messageId, userId, groupId from inbox order by $sortBy"); - while (my ($messageId, $userId, $groupId) = $rs->array) { - if ($user->userId eq $userId || ($groupId && $user->isInGroup($groupId))) { - $counter++; - next if ($counter < $start); - push(@messages, $self->getMessage($messageId)); - last if ($counter >= $end); - } - } - $rs->finish; - return \@messages; + # Otherwise put "pending" messages above "completed" messaged and sort by date descending + else { + $sql = + q{ ( SELECT messageId, status, dateStamp FROM inbox WHERE status="pending" AND groupId IN ( %s ) ORDER BY dateStamp DESC LIMIT %s ) } + . q{ UNION } + . q{ ( SELECT messageId, status, dateStamp FROM inbox WHERE status="pending" AND userId = "%s" ORDER BY dateStamp DESC LIMIT %s ) } + . q{ UNION } + . q{ ( SELECT messageId, status, dateStamp FROM inbox WHERE status="completed" AND groupId IN ( %s ) ORDER BY dateStamp DESC LIMIT %s ) } + . q{ UNION } + . q{ ( SELECT messageId, status, dateStamp FROM inbox WHERE status="completed" AND userId = "%s" ORDER BY dateStamp DESC LIMIT %s ) } + . q{ ORDER BY status="pending" DESC, dateStamp DESC LIMIT %s } + ; + + @bindvars = ( + ( $self->session->db->quoteAndJoin( $user->getGroupIdsRecursive ), $end, + $user->userId, $end, + ) x 2, + $limit, + ); + } + + my $rs = $self->session->db->read( sprintf $sql, @bindvars ); + while ( my ( $messageId ) = $rs->array ) { + push @messages, $self->getMessage( $messageId ); + } + $rs->finish; + + return \@messages; }