diff options
Diffstat (limited to 'Bugzilla')
-rw-r--r-- | Bugzilla/Search.pm | 109 |
1 files changed, 104 insertions, 5 deletions
diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index 9756a428d..10d9d907a 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -24,6 +24,7 @@ # Andreas Franke <afranke@mathweb.org> # Myk Melez <myk@mozilla.org> # Michael Schindler <michael@compressconsult.com> +# Max Kanat-Alexander <mkanat@kerio.com> use strict; @@ -43,17 +44,32 @@ use Bugzilla::Constants; use Date::Format; use Date::Parse; +# Some fields are not sorted on themselves, but on other fields. +# We need to have a list of these fields and what they map to. +# Each field points to an array that contains the fields mapped +# to, in order. +our %specialorder = ( + 'bugs.target_milestone' => [ 'ms_order.sortkey','ms_order.value' ] +); + +# When we add certain fields to the ORDER BY, we need to then add a +# table join to the FROM statement. This hash maps input fields to +# the join statements that ned to be added. +our %specialorderjoin = ( + 'bugs.target_milestone' => 'LEFT JOIN milestones AS ms_order ON ms_order.value = bugs.target_milestone AND ms_order.product_id = bugs.product_id' +); + # Create a new Search # Note that the param argument may be modified by Bugzilla::Search sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; - my $self = { @_ }; + my $self = { @_ }; bless($self, $class); - + $self->init(); - + return $self; } @@ -63,8 +79,13 @@ sub init { my $params = $self->{'params'}; my $user = $self->{'user'} || Bugzilla->user; + my $orderref = $self->{'order'} || 0; + my @inputorder; + @inputorder = @$orderref if $orderref; + my @orderby; + my $debug = 0; - + my @fields; my @supptables; my @wherepart; @@ -1231,6 +1252,26 @@ sub init { } } } + + # The ORDER BY clause goes last, but can require modifications + # to other parts of the query, so we want to create it before we + # write the FROM clause. + foreach my $orderitem (@inputorder) { + BuildOrderBy($orderitem, \@orderby); + } + # Now JOIN the correct tables in the FROM clause. + # This is done separately from the above because it's + # cleaner to do it this way. + foreach my $orderitem (@inputorder) { + # Grab the part without ASC or DESC. + my @splitfield = split(/\s+/, $orderitem); + if ($specialorderjoin{$splitfield[0]}) { + push(@supptables, $specialorderjoin{$splitfield[0]}); + } + # FIXME: Some DBs require ORDER BY items to also + # be in GROUP BY. + } + my %suppseen = ("bugs" => 1); my $suppstring = "bugs"; my @supplist = (" "); @@ -1255,7 +1296,7 @@ sub init { # Make sure we create a legal SQL query. @andlist = ("1 = 1") if !@andlist; - + my $query = "SELECT " . join(', ', @fields) . " FROM $suppstring" . " LEFT JOIN bug_group_map " . @@ -1288,6 +1329,10 @@ sub init { $query .= " HAVING " . join(" AND ", @having); } + if (@orderby) { + $query .= " ORDER BY " . join(',', @orderby); + } + if ($debug) { print "<p><code>" . value_quote($query) . "</code></p>\n"; exit; @@ -1475,4 +1520,58 @@ sub IsValidQueryType } return 0; } + +# BuildOrderBy - Private Subroutine +# This function converts the input order to an "output" order, +# suitable for concatenation to form an ORDER BY clause. Basically, +# it just handles fields that have non-standard sort orders from +# %specialorder. +# Arguments: +# $orderitem - A string. The next value to append to the ORDER BY clause, +# in the format of an item in the 'order' parameter to +# Bugzilla::Search. +# $stringlist - A reference to the list of strings that will be join()'ed +# to make ORDER BY. This is what the subroutine modifies. +# $reverseorder - (Optional) A boolean. TRUE if we should reverse the order +# of the field that we are given (from ASC to DESC or vice-versa). +# +# Explanation of $reverseorder +# ---------------------------- +# The role of $reverseorder is to handle things like sorting by +# "target_milestone DESC". +# Let's say that we had a field "A" that normally translates to a sort +# order of "B ASC, C DESC". If we sort by "A DESC", what we really then +# mean is "B DESC, C ASC". So $reverseorder is only used if we call +# BuildOrderBy recursively, to let it know that we're "reversing" the +# order. That is, that we wanted "A DESC", not "A". +sub BuildOrderBy { + my ($orderitem, $stringlist, $reverseorder) = (@_); + + my @twopart = split(/\s+/, $orderitem); + my $orderfield = $twopart[0]; + my $orderdirection = $twopart[1] || ""; + + if ($reverseorder) { + # If orderdirection is empty or ASC... + if (!$orderdirection || $orderdirection =~ m/asc/i) { + $orderdirection = "DESC"; + } else { + # This has the minor side-effect of making any reversed invalid + # direction into ASC. + $orderdirection = "ASC"; + } + } + + # Handle fields that have non-standard sort orders, from $specialorder. + if ($specialorder{$orderfield}) { + foreach my $subitem (@{$specialorder{$orderfield}}) { + # DESC on a field with non-standard sort order means + # "reverse the normal order for each field that we map to." + BuildOrderBy($subitem, $stringlist, $orderdirection =~ m/desc/i); + } + return; + } + + push(@$stringlist, $orderfield . ' ' . $orderdirection); +} 1; |