[Rt-commit] rt branch, 4.0/joins-bundling, created. rt-4.0.11rc1-23-gf6231dc
Ruslan Zakirov
ruz at bestpractical.com
Thu Apr 4 13:07:43 EDT 2013
The branch, 4.0/joins-bundling has been created
at f6231dcae14a0c115718e03bc7ec891b24a17881 (commit)
- Log -----------------------------------------------------------------
commit f6231dcae14a0c115718e03bc7ec891b24a17881
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu Apr 4 20:03:48 2013 +0400
bundle together watcher searches
it's first attempt at wide bundling of watcher searches.
So far it supports:
* bundling of positive conditions (=, like, is null)
* conditions can be mixed with conditions on other fields:
(Cc.foo = a AND Subject = s) OR (Cc.foo = b AND Subject = s)
The following cases are not bundled while in theory they could:
* Cc = 'foo' OR Requestor = 'bar'
* Cc != 'foo' AND Cc != 'bar'
diff --git a/lib/RT/Tickets.pm b/lib/RT/Tickets.pm
index 3b834e0..961efc4 100644
--- a/lib/RT/Tickets.pm
+++ b/lib/RT/Tickets.pm
@@ -939,13 +939,18 @@ sub _WatcherLimit {
}
$rest{SUBKEY} ||= 'EmailAddress';
- my $groups = $self->_RoleGroupsJoin( Type => $type, Class => $class, New => !$type );
+ my ($groups, $group_members);
+ if ( $rest{'BUNDLE'} ) {
+ ($groups, $group_members) = @{ $rest{'BUNDLE'} };
+ } else {
+ $groups = $self->_RoleGroupsJoin( Type => $type, Class => $class, New => !$type );
+ }
$self->_OpenParen;
if ( $op =~ /^IS(?: NOT)?$/i ) {
# is [not] empty case
- my $group_members = $self->_GroupMembersJoin( GroupsAlias => $groups );
+ $group_members ||= $self->_GroupMembersJoin( GroupsAlias => $groups );
# to avoid joining the table Users into the query, we just join GM
# and make sure we don't match records where group is member of itself
$self->SUPER::Limit(
@@ -983,7 +988,7 @@ sub _WatcherLimit {
$users_obj->RowsPerPage(2);
my @users = @{ $users_obj->ItemsArrayRef };
- my $group_members = $self->_GroupMembersJoin( GroupsAlias => $groups );
+ $group_members ||= $self->_GroupMembersJoin( GroupsAlias => $groups );
if ( @users <= 1 ) {
my $uid = 0;
$uid = $users[0]->id if @users;
@@ -1034,7 +1039,7 @@ sub _WatcherLimit {
} else {
# positive condition case
- my $group_members = $self->_GroupMembersJoin(
+ $group_members ||= $self->_GroupMembersJoin(
GroupsAlias => $groups, New => 1, Left => 0
);
my $users = $self->Join(
@@ -1054,6 +1059,7 @@ sub _WatcherLimit {
);
}
$self->_CloseParen;
+ return ($groups, $group_members);
}
sub _RoleGroupsJoin {
diff --git a/lib/RT/Tickets_SQL.pm b/lib/RT/Tickets_SQL.pm
index 608862a..7d57143 100644
--- a/lib/RT/Tickets_SQL.pm
+++ b/lib/RT/Tickets_SQL.pm
@@ -171,19 +171,42 @@ sub _parser {
my @bundle;
my $ea = '';
+ my %sub_tree;
+ my $depth = 0;
+
my %callback;
$callback{'OpenParen'} = sub {
$self->_close_bundle(@bundle); @bundle = ();
- $self->_OpenParen
+ $self->_OpenParen;
+ $depth++;
+ push @$_, '(' foreach values %sub_tree;
};
$callback{'CloseParen'} = sub {
$self->_close_bundle(@bundle); @bundle = ();
$self->_CloseParen;
+ $depth--;
+ foreach my $list ( values %sub_tree ) {
+ if ( $list->[-1] eq '(' ) {
+ pop @$list;
+ pop @$list if $list->[-1] =~ /^(?:AND|OR)$/i;
+ }
+ elsif ( ref $list->[-1] && $list->[-2] eq '(' ) {
+ $list->[-1] = pop @$list;
+ }
+ else {
+ push @$list, ')';
+ }
+ }
+ };
+ $callback{'EntryAggregator'} = sub {
+ $ea = $_[0] || '';
+ push @$_, $ea foreach values %sub_tree;
};
- $callback{'EntryAggregator'} = sub { $ea = $_[0] || '' };
$callback{'Condition'} = sub {
my ($key, $op, $value) = @_;
+ my ($negative_op, $null_op, $inv_op, $range_op)
+ = $self->ClassifySQLOperation( $op );
# key has dot then it's compound variant and we have subkey
my $subkey = '';
($key, $subkey) = ($1, $2) if $key =~ /^([^\.]+)\.(.+)$/;
@@ -225,10 +248,32 @@ sub _parser {
}
else {
$self->_close_bundle(@bundle); @bundle = ();
- $sub->( $self, $key, $op, $value,
+ my @res; my $bundle_with;
+ if ( $class eq 'WATCHERFIELD' && $key ne 'Owner' && !$negative_op && (!$null_op || $subkey) ) {
+ if ( !$sub_tree{$key} ) {
+ $sub_tree{$key} = [ ('(')x$depth, \@res ];
+ } else {
+ $bundle_with = $self->_check_bundling_possibility( @{ $sub_tree{$key} } );
+ unless ( $bundle_with ) {
+ if ( $sub_tree{$key}[-1] =~ /^AND$/i ) {
+ pop @{ $sub_tree{$key} };
+ }
+ else {
+ push @{ $sub_tree{$key} }, \@res;
+ }
+ } else {
+ pop @{ $sub_tree{$key} } if $sub_tree{$key}[-1] =~ /^(?:AND|OR)$/i;
+ }
+ }
+ }
+ else {
+ pop @$_ foreach grep @$_ && $_->[-1] =~ /^(?:AND|OR)$/i, values %sub_tree;
+ }
+ @res = $sub->( $self, $key, $op, $value,
SUBCLAUSE => '', # don't need anymore
ENTRYAGGREGATOR => $ea,
SUBKEY => $subkey,
+ BUNDLE => $bundle_with,
);
}
$self->{_sql_looking_at}{lc $key} = 1;
@@ -238,6 +283,24 @@ sub _parser {
$self->_close_bundle(@bundle); @bundle = ();
}
+sub _check_bundling_possibility {
+ my $self = shift;
+ my @list = reverse @_;
+ while (my $e = shift @list) {
+ next if $e eq '(';
+ if ( lc($e) eq 'and' ) {
+ return undef;
+ }
+ elsif ( lc($e) eq 'or' ) {
+ return shift @list;
+ }
+ else {
+ die "boo";
+ }
+ }
+ return undef;
+}
+
=head2 ClausesToSQL
=cut
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list