summaryrefslogtreecommitdiff
path: root/rt/lib/RT/SQL.pm
diff options
context:
space:
mode:
Diffstat (limited to 'rt/lib/RT/SQL.pm')
-rw-r--r--rt/lib/RT/SQL.pm302
1 files changed, 0 insertions, 302 deletions
diff --git a/rt/lib/RT/SQL.pm b/rt/lib/RT/SQL.pm
deleted file mode 100644
index bf48bda50..000000000
--- a/rt/lib/RT/SQL.pm
+++ /dev/null
@@ -1,302 +0,0 @@
-# BEGIN BPS TAGGED BLOCK {{{
-#
-# COPYRIGHT:
-#
-# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
-# <jesse@bestpractical.com>
-#
-# (Except where explicitly superseded by other copyright notices)
-#
-#
-# LICENSE:
-#
-# This work is made available to you under the terms of Version 2 of
-# the GNU General Public License. A copy of that license should have
-# been provided with this software, but in any event can be snarfed
-# from www.gnu.org.
-#
-# This work is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301 or visit their web page on the internet at
-# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
-#
-#
-# CONTRIBUTION SUBMISSION POLICY:
-#
-# (The following paragraph is not intended to limit the rights granted
-# to you to modify and distribute this software under the terms of
-# the GNU General Public License and is only of importance to you if
-# you choose to contribute your changes and enhancements to the
-# community by submitting them to Best Practical Solutions, LLC.)
-#
-# By intentionally submitting any modifications, corrections or
-# derivatives to this work, or any other work intended for use with
-# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-# you are the copyright holder for those contributions and you grant
-# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
-# royalty-free, perpetual, license to use, copy, create derivative
-# works based on those contributions, and sublicense and distribute
-# those contributions and any derivatives thereof.
-#
-# END BPS TAGGED BLOCK }}}
-
-package RT::SQL;
-
-use strict;
-use warnings;
-
-use constant HAS_BOOLEAN_PARSER => do {
- local $@;
- eval { require Parse::BooleanLogic; 1 }
-};
-
-# States
-use constant VALUE => 1;
-use constant AGGREG => 2;
-use constant OP => 4;
-use constant OPEN_PAREN => 8;
-use constant CLOSE_PAREN => 16;
-use constant KEYWORD => 32;
-my @tokens = qw[VALUE AGGREGATOR OPERATOR OPEN_PAREN CLOSE_PAREN KEYWORD];
-
-use Regexp::Common qw /delimited/;
-my $re_aggreg = qr[(?i:AND|OR)];
-my $re_delim = qr[$RE{delimited}{-delim=>qq{\'\"}}];
-my $re_value = qr[\d+|NULL|$re_delim];
-my $re_keyword = qr[[{}\w\.]+|$re_delim];
-my $re_op = qr[=|!=|>=|<=|>|<|(?i:IS NOT)|(?i:IS)|(?i:NOT LIKE)|(?i:LIKE)]; # long to short
-my $re_open_paren = qr[\(];
-my $re_close_paren = qr[\)];
-
-sub ParseToArray {
- my ($string) = shift;
-
- my ($tree, $node, @pnodes);
- $node = $tree = [];
-
- my %callback;
- $callback{'OpenParen'} = sub { push @pnodes, $node; $node = []; push @{ $pnodes[-1] }, $node };
- $callback{'CloseParen'} = sub { $node = pop @pnodes };
- $callback{'EntryAggregator'} = sub { push @$node, $_[0] };
- $callback{'Condition'} = sub { push @$node, { key => $_[0], op => $_[1], value => $_[2] } };
-
- Parse($string, \%callback);
- return $tree;
-}
-
-sub Parse {
- my ($string, $cb) = @_;
- $string = '' unless defined $string;
-
- my $want = KEYWORD | OPEN_PAREN;
- my $last = 0;
-
- my $depth = 0;
- my ($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_open_paren
- |$re_close_paren
- )/iogx )
- {
- my $match = $1;
-
- # Highest priority is last
- my $current = 0;
- $current = OP if ($want & OP) && $match =~ /^$re_op$/io;
- $current = VALUE if ($want & VALUE) && $match =~ /^$re_value$/io;
- $current = KEYWORD if ($want & KEYWORD) && $match =~ /^$re_keyword$/io;
- $current = AGGREG if ($want & AGGREG) && $match =~ /^$re_aggreg$/io;
- $current = OPEN_PAREN if ($want & OPEN_PAREN) && $match =~ /^$re_open_paren$/io;
- $current = CLOSE_PAREN if ($want & CLOSE_PAREN) && $match =~ /^$re_close_paren$/io;
-
-
- unless ($current && $want & $current) {
- my $tmp = substr($string, 0, pos($string)- length($match));
- $tmp .= '>'. $match .'<--here'. substr($string, pos($string));
- my $msg = "Wrong query, expecting a ". _BitmaskToString($want) ." in '$tmp'";
- return $cb->{'Error'}->( $msg ) if $cb->{'Error'};
- die $msg;
- }
-
- # State Machine:
-
- # Parens are highest priority
- if ( $current & OPEN_PAREN ) {
- $cb->{'OpenParen'}->();
- $depth++;
- $want = KEYWORD | OPEN_PAREN;
- }
- elsif ( $current & CLOSE_PAREN ) {
- $cb->{'CloseParen'}->();
- $depth--;
- $want = AGGREG;
- $want |= CLOSE_PAREN if $depth;
- }
- elsif ( $current & AGGREG ) {
- $cb->{'EntryAggregator'}->( $match );
- $want = KEYWORD | OPEN_PAREN;
- }
- elsif ( $current & KEYWORD ) {
- $key = $match;
- $want = OP;
- }
- elsif ( $current & OP ) {
- $op = $match;
- $want = VALUE;
- }
- elsif ( $current & VALUE ) {
- $value = $match;
-
- # Remove surrounding quotes and unescape escaped
- # characters from $key, $match
- for ( $key, $value ) {
- if ( /$re_delim/o ) {
- substr($_,0,1) = "";
- substr($_,-1,1) = "";
- }
- s!\\(.)!$1!g;
- }
-
- $cb->{'Condition'}->( $key, $op, $value );
-
- ($key,$op,$value) = ("","","");
- $want = AGGREG;
- $want |= CLOSE_PAREN if $depth;
- } else {
- my $msg = "Query parser is lost";
- return $cb->{'Error'}->( $msg ) if $cb->{'Error'};
- die $msg;
- }
-
- $last = $current;
- } # while
-
- unless( !$last || $last & (CLOSE_PAREN | VALUE) ) {
- my $msg = "Incomplete query, last element ("
- . _BitmaskToString($last)
- . ") is not CLOSE_PAREN or VALUE in '$string'";
- return $cb->{'Error'}->( $msg ) if $cb->{'Error'};
- die $msg;
- }
-
- if( $depth ) {
- my $msg = "Incomplete query, $depth paren(s) isn't closed in '$string'";
- return $cb->{'Error'}->( $msg ) if $cb->{'Error'};
- die $msg;
- }
-}
-
-sub _BitmaskToString {
- my $mask = shift;
-
- my @res;
- for( my $i = 0; $i<@tokens; $i++ ) {
- next unless $mask & (1<<$i);
- push @res, $tokens[$i];
- }
-
- my $tmp = join ', ', splice @res, 0, -1;
- unshift @res, $tmp if $tmp;
- return join ' or ', @res;
-}
-
-sub PossibleCustomFields {
- my %args = (Query => undef, CurrentUser => undef, @_);
-
- my $cfs = RT::CustomFields->new( $args{'CurrentUser'} );
- my $ocf_alias = $cfs->_OCFAlias;
- $cfs->LimitToLookupType( 'RT::Queue-RT::Ticket' );
-
- my $tree;
- if ( HAS_BOOLEAN_PARSER ) {
- $tree = Parse::BooleanLogic->filter(
- RT::SQL::ParseToArray( $args{'Query'} ),
- sub { $_[0]->{'key'} =~ /^Queue(?:\z|\.)/ },
- );
- }
- if ( $tree && @$tree ) {
- my $clause = 'QUEUES';
- my $queue_alias = $cfs->Join(
- TYPE => 'LEFT',
- ALIAS1 => $ocf_alias,
- FIELD1 => 'ObjectId',
- TABLE2 => 'Queues',
- FIELD2 => 'id',
- );
- $cfs->_OpenParen($clause);
- $cfs->Limit(
- SUBCLAUSE => $clause,
- ENTRYAGGREGATOR => 'AND',
- ALIAS => $ocf_alias,
- FIELD => 'ObjectId',
- VALUE => 0,
- );
- $cfs->_OpenParen($clause);
-
- my $ea = 'OR';
- Parse::BooleanLogic->walk(
- $tree,
- {
- open_paren => sub { $cfs->_OpenParen($clause) },
- close_paren => sub { $cfs->_CloseParen($clause) },
- operator => sub { $ea = $_[0] },
- operand => sub {
- my ($key, $op, $value) = @{$_[0]}{'key', 'op', 'value'};
- my (undef, @sub) = split /\./, $key;
- push @sub, $value =~ /\D/? 'Name' : 'id'
- unless @sub;
-
- die "Couldn't handle ". join('.', 'Queue', @sub) if @sub > 1;
- $cfs->Limit(
- SUBCLAUSE => $clause,
- ENTRYAGGREGATOR => $ea,
- ALIAS => $queue_alias,
- FIELD => $sub[0],
- OPERATOR => $op,
- VALUE => $value,
- );
- },
- }
- );
-
- $cfs->_CloseParen($clause);
- $cfs->_CloseParen($clause);
- } else {
- $cfs->Limit(
- ENTRYAGGREGATOR => 'AND',
- ALIAS => $ocf_alias,
- FIELD => 'ObjectId',
- OPERATOR => 'IS NOT',
- VALUE => 'NULL',
- );
- }
- return $cfs;
-}
-
-
-eval "require RT::SQL_Vendor";
-if ($@ && $@ !~ qr{^Can't locate RT/SQL_Vendor.pm}) {
- die $@;
-};
-
-eval "require RT::SQL_Local";
-if ($@ && $@ !~ qr{^Can't locate RT/SQL_Local.pm}) {
- die $@;
-};
-
-1;