From cd2776192dbaf1d21353f400eaf42d01e66b33f4 Mon Sep 17 00:00:00 2001 From: Byron Jones Date: Thu, 18 Apr 2013 01:15:46 +0800 Subject: Bug 828344: Make "contains all of the words" look for all words within the same comment or flag r=LpSolit, a=LpSolit --- Bugzilla/Search.pm | 148 ++++++++++++++++++++++++++++++++--------- Bugzilla/Search/Clause.pm | 38 ++++++----- Bugzilla/Search/Quicksearch.pm | 4 +- 3 files changed, 139 insertions(+), 51 deletions(-) (limited to 'Bugzilla') diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index 658b85f99..51520bb55 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -268,12 +268,14 @@ use constant OPERATOR_FIELD_OVERRIDE => { }, dependson => MULTI_SELECT_OVERRIDE, keywords => MULTI_SELECT_OVERRIDE, - 'flagtypes.name' => MULTI_SELECT_OVERRIDE, + 'flagtypes.name' => { + _non_changed => \&_flagtypes_nonchanged, + }, longdesc => { - %{ MULTI_SELECT_OVERRIDE() }, changedby => \&_long_desc_changedby, changedbefore => \&_long_desc_changedbefore_after, changedafter => \&_long_desc_changedbefore_after, + _non_changed => \&_long_desc_nonchanged, }, 'longdescs.count' => { changedby => \&_long_desc_changedby, @@ -767,8 +769,16 @@ sub _sql { my ($self) = @_; return $self->{sql} if $self->{sql}; my $dbh = Bugzilla->dbh; - + my ($joins, $clause) = $self->_charts_to_conditions(); + + if (!$clause->as_string + && !Bugzilla->params->{'search_allow_no_criteria'} + && !$self->{allow_unlimited}) + { + ThrowUserError('buglist_parameters_required'); + } + my $select = join(', ', $self->_sql_select); my $from = $self->_sql_from($joins); my $where = $self->_sql_where($clause); @@ -1308,14 +1318,7 @@ sub _sql_where { # SQL a bit more readable for debugging. my $where = join("\n AND ", $self->_standard_where); my $clause_sql = $main_clause->as_string; - if ($clause_sql) { - $where .= "\n AND " . $clause_sql; - } - elsif (!Bugzilla->params->{'search_allow_no_criteria'} - && !$self->{allow_unlimited}) - { - ThrowUserError('buglist_parameters_required'); - } + $where .= "\n AND " . $clause_sql if $clause_sql; return $where; } @@ -1994,24 +1997,13 @@ sub _quote_unless_numeric { sub build_subselect { my ($outer, $inner, $table, $cond, $negate) = @_; - - if ($table eq 'longdescs') { - # There is no index on the longdescs.thetext column and so it takes - # a long time to scan the whole table unconditionally. For this table, - # we return the subselect and let the DB optimizer restrict the search - # to some given bug list only based on other search criteria available. - my $not = $negate ? "NOT" : ""; - return "$outer $not IN (SELECT DISTINCT $inner FROM $table WHERE $cond)"; - } - else { - # Execute subselects immediately to avoid dependent subqueries, which are - # large performance hits on MySql - my $q = "SELECT DISTINCT $inner FROM $table WHERE $cond"; - my $dbh = Bugzilla->dbh; - my $list = $dbh->selectcol_arrayref($q); - return $negate ? "1=1" : "1=2" unless @$list; - return $dbh->sql_in($outer, $list, $negate); - } + # Execute subselects immediately to avoid dependent subqueries, which are + # large performance hits on MySql + my $q = "SELECT DISTINCT $inner FROM $table WHERE $cond"; + my $dbh = Bugzilla->dbh; + my $list = $dbh->selectcol_arrayref($q); + return $negate ? "1=1" : "1=2" unless @$list; + return $dbh->sql_in($outer, $list, $negate); } # Used by anyexact to get the list of input values. This allows us to @@ -2432,14 +2424,51 @@ sub _long_desc_changedbefore_after { } } +sub _long_desc_nonchanged { + my ($self, $args) = @_; + my ($chart_id, $operator, $value, $joins, $bugs_table) = + @$args{qw(chart_id operator value joins bugs_table)}; + my $dbh = Bugzilla->dbh; + + my $table = "longdescs_$chart_id"; + my $join_args = { + chart_id => $chart_id, + sequence => $chart_id, + field => 'longdesc', + full_field => "$table.thetext", + operator => $operator, + value => $value, + all_values => $value, + quoted => $dbh->quote($value), + joins => [], + bugs_table => $bugs_table, + }; + $self->_do_operator_function($join_args); + + # If the user is not part of the insiders group, they cannot see + # private comments + if (!$self->_user->is_insider) { + $join_args->{term} .= " AND $table.isprivate = 0"; + } + + my $join = { + table => 'longdescs', + as => $table, + extra => [ $join_args->{term} ], + }; + push(@$joins, $join); + + $args->{term} = "$table.comment_id IS NOT NULL"; +} + sub _content_matches { my ($self, $args) = @_; my ($chart_id, $joins, $fields, $operator, $value) = @$args{qw(chart_id joins fields operator value)}; my $dbh = Bugzilla->dbh; - + # "content" is an alias for columns containing text for which we - # can search a full-text index and retrieve results by relevance, + # can search a full-text index and retrieve results by relevance, # currently just bug comments (and summaries to some degree). # There's only one way to search a full-text index, so we only # accept the "matches" operator, which is specific to full-text @@ -2694,6 +2723,63 @@ sub _multiselect_multiple { } } +sub _flagtypes_nonchanged { + my ($self, $args) = @_; + my ($chart_id, $operator, $value, $joins, $bugs_table) = + @$args{qw(chart_id operator value joins bugs_table)}; + my $dbh = Bugzilla->dbh; + my $join; + + # join to the attachments table + my $attach_table = "attachments_$chart_id"; + $join = { + table => 'attachments', + as => $attach_table, + from => "$bugs_table.bug_id", + to => "bug_id", + extra => [ ($self->_user->is_insider ? '' : "$attach_table.isprivate = 0") ], + }; + push(@$joins, $join); + + # join to the flags table + my $flags_table = "flags_$chart_id"; + $join = { + table => 'flags', + as => $flags_table, + from => "$bugs_table.bug_id", + to => "bug_id", + extra => [ "($flags_table.attach_id = $attach_table.attach_id " . + " OR $flags_table.attach_id IS NULL)" ], + }; + push(@$joins, $join); + + # join to the flagtypes table + my $flagtypes_table = "flagtypes_$chart_id"; + $join = { + table => 'flagtypes', + as => $flagtypes_table, + from => "$flags_table.type_id", + to => "id", + }; + push(@$joins, $join); + + # join to the profiles table for the requestee + my $flag_profile_table = "flag_profiles_$chart_id"; + $join = { + table => 'profiles', + as => $flag_profile_table, + from => "$flags_table.requestee_id", + to => "userid", + }; + push(@$joins, $join); + + $args->{full_field} = $dbh->sql_string_concat("$flagtypes_table.name", + "$flags_table.status", + "COALESCE($flag_profile_table.login_name, '')"); + + $self->_do_operator_function($args); +} + sub _multiselect_nonchanged { my ($self, $args) = @_; my ($chart_id, $joins, $field, $operator) = diff --git a/Bugzilla/Search/Clause.pm b/Bugzilla/Search/Clause.pm index 7bfd52015..9d3d690a3 100644 --- a/Bugzilla/Search/Clause.pm +++ b/Bugzilla/Search/Clause.pm @@ -86,25 +86,29 @@ sub walk_conditions { sub as_string { my ($self) = @_; - my @strings; - foreach my $child (@{ $self->children }) { - next if $child->isa(__PACKAGE__) && !$child->has_translated_conditions; - next if $child->isa('Bugzilla::Search::Condition') - && !$child->translated; - - my $string = $child->as_string; - if ($self->joiner eq 'AND') { - $string = "( $string )" if $string =~ /OR/; - } - else { - $string = "( $string )" if $string =~ /AND/; + if (!$self->{sql}) { + my @strings; + foreach my $child (@{ $self->children }) { + next if $child->isa(__PACKAGE__) && !$child->has_translated_conditions; + next if $child->isa('Bugzilla::Search::Condition') + && !$child->translated; + + my $string = $child->as_string; + next unless $string; + if ($self->joiner eq 'AND') { + $string = "( $string )" if $string =~ /OR/; + } + else { + $string = "( $string )" if $string =~ /AND/; + } + push(@strings, $string); } - push(@strings, $string); + + my $sql = join(' ' . $self->joiner . ' ', @strings); + $sql = "NOT( $sql )" if $sql && $self->negate; + $self->{sql} = $sql; } - - my $sql = join(' ' . $self->joiner . ' ', @strings); - $sql = "NOT( $sql )" if $sql && $self->negate; - return $sql; + return $self->{sql}; } # Search.pm converts URL parameters to Clause objects. This helps do the diff --git a/Bugzilla/Search/Quicksearch.pm b/Bugzilla/Search/Quicksearch.pm index fc109a640..d073720a1 100644 --- a/Bugzilla/Search/Quicksearch.pm +++ b/Bugzilla/Search/Quicksearch.pm @@ -364,10 +364,8 @@ sub _handle_field_names { my ($or_operand, $negate, $unknownFields, $ambiguous_fields) = @_; # Flag and requestee shortcut - if ($or_operand =~ /^(?:flag:)?([^\?]+\?)([^\?]*)$/) { + if ($or_operand =~ /^(?:flag:)?([^\?]+\?[^\?]*)$/) { addChart('flagtypes.name', 'substring', $1, $negate); - $chart++; $and = $or = 0; # Next chart for boolean AND - addChart('requestees.login_name', 'substring', $2, $negate); return 1; } -- cgit v1.2.3-24-g4f1b