+sub ParseSQL {
+ my $self = shift;
+ my %args = (
+ Query => '',
+ CurrentUser => '', #XXX: Hack
+ @_
+ );
+ my $string = $args{'Query'};
+
+ my @results;
+
+ my %field = %{ RT::Tickets->new( $args{'CurrentUser'} )->FIELDS };
+ my %lcfield = map { ( lc($_) => $_ ) } keys %field;
+
+ my $node = $self;
+
+ my %callback;
+ $callback{'OpenParen'} = sub {
+ $node = __PACKAGE__->new( 'AND', $node );
+ };
+ $callback{'CloseParen'} = sub { $node = $node->getParent };
+ $callback{'EntryAggregator'} = sub { $node->setNodeValue( $_[0] ) };
+ $callback{'Condition'} = sub {
+ my ($key, $op, $value) = @_;
+
+ my ($main_key) = split /[.]/, $key;
+
+ my $class;
+ if ( exists $lcfield{ lc $main_key } ) {
+ $key =~ s/^[^.]+/ $lcfield{ lc $main_key } /e;
+ ($main_key) = split /[.]/, $key; # make the case right
+ $class = $field{ $main_key }->[0];
+ }
+ unless( $class ) {
+ push @results, [ $args{'CurrentUser'}->loc("Unknown field: [_1]", $key), -1 ]
+ }
+
+ if ( lc $op eq 'is' || lc $op eq 'is not' ) {
+ $value = 'NULL'; # just fix possible mistakes here
+ } elsif ( $value !~ /^[+-]?[0-9]+$/ ) {
+ $value =~ s/(['\\])/\\$1/g;
+ $value = "'$value'";
+ }
+
+ if ($key =~ s/(['\\])/\\$1/g or $key =~ /[^{}\w\.]/) {
+ $key = "'$key'";
+ }
+
+ my $clause = { Key => $key, Op => $op, Value => $value };
+ $node->addChild( __PACKAGE__->new( $clause ) );
+ };
+ $callback{'Error'} = sub { push @results, @_ };
+
+ require RT::SQL;
+ RT::SQL::Parse($string, \%callback);
+ return @results;
+}