X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=rt%2Flib%2FRT%2FTickets_Overlay_SQL.pm;h=629e6da2d4bb170ad0b2ce678abbe1994523a5ea;hb=35effa1bf4ac902547615c816960bbc8db8e7256;hp=d78a56db3d4de806b9e92d940e1991a6384b456b;hpb=0ebeec96313dd7edfca340f01f8fbbbac1f4aa1d;p=freeside.git diff --git a/rt/lib/RT/Tickets_Overlay_SQL.pm b/rt/lib/RT/Tickets_Overlay_SQL.pm index d78a56db3..629e6da2d 100644 --- a/rt/lib/RT/Tickets_Overlay_SQL.pm +++ b/rt/lib/RT/Tickets_Overlay_SQL.pm @@ -29,6 +29,10 @@ use warnings; my %FIELDS = %{FIELDS()}; my %dispatch = %{dispatch()}; +my %can_bundle = %{can_bundle()}; + +# Lower Case version of FIELDS, for case insensitivity +my %lcfields = map { ( lc($_) => $_ ) } (keys %FIELDS); sub _InitSQL { my $self = shift; @@ -119,20 +123,57 @@ my $re_keyword = qr[$RE{delimited}{-delim=>qq{\'\"}}|(?:\{|\}|\w|\.)+]; my $re_op = qr[=|!=|>=|<=|>|<|(?i:IS NOT)|(?i:IS)|(?i:NOT LIKE)|(?i:LIKE)]; # long to short my $re_paren = qr'\(|\)'; +sub _close_bundle +{ + my ($self, @bundle) = @_; + return unless @bundle; + if (@bundle == 1) { + $bundle[0]->{dispatch}->( + $self, + $bundle[0]->{key}, + $bundle[0]->{op}, + $bundle[0]->{val}, + SUBCLAUSE => "", + ENTRYAGGREGATOR => $bundle[0]->{ea}, + SUBKEY => $bundle[0]->{subkey}, + ); + } else { + my @args; + for my $chunk (@bundle) { + push @args, [ + $chunk->{key}, + $chunk->{op}, + $chunk->{val}, + SUBCLAUSE => "", + ENTRYAGGREGATOR => $chunk->{ea}, + SUBKEY => $chunk->{subkey}, + ]; + } + $bundle[0]->{dispatch}->( + $self, \@args, + ); + } +} + sub _parser { my ($self,$string) = @_; my $want = KEYWORD | PAREN; my $last = undef; my $depth = 0; + my @bundle; my ($ea,$key,$op,$value) = ("","","",""); + # order of matches in the RE is important.. op should come early, + # because it has spaces in it. otherwise "NOT LIKE" might be parsed + # as a keyword or value. + while ($string =~ /( $re_aggreg + |$re_op |$re_keyword |$re_value - |$re_op |$re_paren )/igx ) { my $val = $1; @@ -156,10 +197,12 @@ sub _parser { # Parens are highest priority if ($current & PAREN) { if ($val eq "(") { + $self->_close_bundle(@bundle); @bundle = (); $depth++; $self->_OpenParen; } else { + $self->_close_bundle(@bundle); @bundle = (); $depth--; $self->_CloseParen; } @@ -204,10 +247,9 @@ sub _parser { } my $class; - my ($stdkey) = grep { /^$key$/i } (keys %FIELDS); - if ($stdkey && exists $FIELDS{$stdkey}) { + if (exists $lcfields{lc $key}) { + $key = $lcfields{lc $key}; $class = $FIELDS{$key}->[0]; - $key = $stdkey; } # no longer have a default, since CF's are now a real class, not fallthrough # fixme: "default class" is not Generic. @@ -219,20 +261,37 @@ sub _parser { die "No such dispatch method: $class" unless exists $dispatch{$class}; my $sub = $dispatch{$class} || die;; - $sub->( - $self, - $key, - $op, - $val, - SUBCLAUSE => "", # don't need anymore - ENTRYAGGREGATOR => $ea || "", - SUBKEY => $subkey, - ); + if ($can_bundle{$class} && + (!@bundle || + ($bundle[-1]->{dispatch} == $sub && + $bundle[-1]->{key} eq $key && + $bundle[-1]->{subkey} eq $subkey))) + { + push @bundle, { + dispatch => $sub, + key => $key, + op => $op, + val => $val, + ea => $ea || "", + subkey => $subkey, + }; + } else { + $self->_close_bundle(@bundle); @bundle = (); + $sub->( + $self, + $key, + $op, + $val, + SUBCLAUSE => "", # don't need anymore + ENTRYAGGREGATOR => $ea || "", + SUBKEY => $subkey, + ); + } $self->{_sql_looking_at}{lc $key} = 1; - + ($ea,$key,$op,$value) = ("","","",""); - + $want = PAREN | AGGREG; } else { die "I'm lost"; @@ -241,6 +300,8 @@ sub _parser { $last = $current; } # while + $self->_close_bundle(@bundle); @bundle = (); + die "Incomplete query" unless (($want | PAREN) || ($want | KEYWORD)); @@ -330,6 +391,10 @@ sub FromSQL { VALUE => 'ticket'); } + # We never ever want to show deleted tickets + $self->SUPER::Limit(FIELD => 'Status' , OPERATOR => '!=', VALUE => 'deleted'); + + # set SB's dirty flag $self->{'must_redo_search'} = 1; $self->{'RecalcTicketLimits'} = 0;