2010-04-27 21:26:52 +04:00
#!/usr/bin/perl
2014-08-18 16:49:59 +04:00
# External SQL interface to Bugzilla Saved Searches (originally CustIS Bug 61728)
2014-08-13 17:19:13 +04:00
# License: Dual-license GPL 3.0+ or MPL 1.1+
2014-08-18 16:49:59 +04:00
# Author(s): Vitaliy Filippov <vitalif@mail.ru>
2014-08-13 17:19:13 +04:00
2014-07-30 19:13:58 +04:00
# FIXME: Add UI for managing views
2010-04-27 21:26:52 +04:00
2014-08-18 16:49:59 +04:00
package Bugzilla::Views ;
2010-04-27 21:26:52 +04:00
use strict ;
2014-08-13 17:19:13 +04:00
use Bugzilla::Util ;
2010-04-27 21:26:52 +04:00
use Bugzilla::User ;
use Bugzilla::Search ;
2011-07-28 21:16:12 +04:00
# MySQL has a limitation on views! :-(
# Views in MySQL cannot include a subquery in the FROM clause.
2013-04-02 16:52:30 +04:00
# We bypass it by creating a view for every such subquery.
2011-07-28 21:16:12 +04:00
sub recurse_create_view
{
my ( $ dbh , $ name , $ sql , $ index ) = @ _ ;
# We need recursive regular expressions, available from Perl 5.10.0
require 5.010 ;
my $ myname = $ name ;
if ( ! $ index )
{
my $ i = 0 ;
$ index = \ $ i ;
}
else
{
$ myname . = '_' . $$ index ;
}
# Match and replace subqueries in the FROM part of the query
$ sql =~ s / ( FROM | JOIN ) \ s * \ ( \ s * SELECT ( ( ? :
[ ^ \ ( \ ) \ " \ ' \ \ ] + |
\ " ( ? : ( ? : [ ^ \ " \ \ ] + | \ \ [ \ " \ \ ] ) * ) \ " |
\ ' ( ? : ( ? : [ ^ \ ' \ \ ] + | \ \ [ \ ' \ \ ] ) * ) \ ' |
\ ( ( ? 2 ) \ )
) + ) \ ) /($$index++), "$1 ".recurse_create_view($dbh, $name, "SELECT$2", $index)/g exiso ;
$ dbh - > do ( "DROP VIEW IF EXISTS $myname" ) ;
$ dbh - > do ( "CREATE SQL SECURITY DEFINER VIEW $myname AS $sql" ) ;
return $ myname ;
}
2011-02-03 19:16:34 +03:00
# Refresh views, optionally only for $users = [ 'username@domain.org', ... ]
2014-08-18 16:49:59 +04:00
# FIXME @domain.org should not be stripped from the username in the name of view
2010-10-22 21:06:56 +04:00
sub refresh_some_views
2010-04-27 21:26:52 +04:00
{
my ( $ users ) = @ _ ;
2014-08-18 16:49:59 +04:00
return if Bugzilla - > params - > { ext_disable_refresh_views } ;
2014-06-20 14:42:31 +04:00
my % u ;
for ( @ { $ users || [] } )
{
2014-08-18 16:49:59 +04:00
s/\@.*$//so ;
2014-06-20 14:42:31 +04:00
$ _ = lc $ _ ;
s/[^a-z0-9]+/_/giso ;
$ _ = "_$_" if ! /^[a-z]/ ;
$ u { $ _ } = 1 ;
}
2010-04-27 21:26:52 +04:00
my $ dbh = Bugzilla - > dbh ;
2015-01-15 18:21:07 +03:00
return unless ( ref $ dbh ) - > can ( 'real_table_list' ) ;
2010-12-03 21:03:05 +03:00
my $ r = $ dbh - > real_table_list ( 'view$%$bugs' , 'VIEW' ) ;
2011-02-03 19:16:34 +03:00
# Save current user
my $ old_user = Bugzilla - > user ;
2010-04-27 21:26:52 +04:00
for ( @$ r )
{
2011-02-03 19:16:34 +03:00
# Determine user
2010-04-27 21:26:52 +04:00
my ( undef , $ user , $ query ) = split /\$/ , $ _ , - 1 ;
! % u || $ u { $ user } or next ;
2014-06-20 14:42:31 +04:00
my $ q = $ user ;
$ q =~ tr /_/ % / ;
my ( $ userid ) = $ dbh - > selectrow_array ( 'SELECT userid FROM profiles WHERE login_name LIKE ? ORDER BY userid LIMIT 1' , undef , $ q . '@%' ) ;
2010-04-27 21:26:52 +04:00
$ userid or next ;
my $ userobj = Bugzilla::User - > new ( $ userid ) or next ;
2011-02-03 19:16:34 +03:00
# Determine saved search
2014-06-20 14:42:31 +04:00
$ q = $ query ;
2011-02-14 19:29:16 +03:00
$ q =~ tr /_/ % / ;
( $ q ) = $ dbh - > selectrow_array ( 'SELECT name FROM namedqueries WHERE userid=? AND name LIKE ? LIMIT 1' , undef , $ userid , $ q ) ;
$ q or next ;
2014-07-24 18:12:49 +04:00
my $ storedquery = Bugzilla::Search::Saved - > new ( { name = > $ q , user = > $ userid } ) or next ;
$ storedquery = http_decode_query ( $ storedquery - > query ) ;
2011-02-03 19:16:34 +03:00
# get SQL code
2010-04-27 21:26:52 +04:00
my $ search = new Bugzilla:: Search (
2014-07-21 16:23:16 +04:00
params = > $ storedquery ,
fields = > [ 'bug_id' , grep { $ _ ne 'bug_id' } split ( /[ ,]+/ , $ storedquery - > { columnlist } || '' ) ] ,
2010-04-27 21:26:52 +04:00
user = > $ userobj ,
) or next ;
2011-07-28 21:16:12 +04:00
# Re-create views
my $ drop = "DROP VIEW IF EXISTS view\$$user\$$query\$" ;
my $ create = "CREATE VIEW view\$$user\$$query\$" ;
my $ bugid_query = $ search - > bugid_query ;
my $ bugids = "view\$$user\$$query\$bugids" ;
if ( $ dbh - > isa ( 'Bugzilla::DB::Mysql' ) )
{
$ create = "CREATE SQL SECURITY DEFINER VIEW view\$$user\$$query\$" ;
recurse_create_view ( $ dbh , $ bugids , $ bugid_query ) ;
}
else
{
$ dbh - > do ( $ drop . 'bugids' ) ;
$ dbh - > do ( "CREATE VIEW $bugids AS $bugid_query" ) ;
}
my $ sql = $ search - > getSQL ;
$ sql =~ s/\(\s*\Q$bugid_query\E\s*\)/$bugids/s ;
$ dbh - > do ( $ drop . 'bugs' ) ;
$ dbh - > do ( $ drop . 'longdescs' ) ;
$ dbh - > do ( $ drop . 'bugs_activity' ) ;
$ dbh - > do ( $ create . 'bugs AS ' . $ sql ) ;
2016-07-05 12:16:15 +03:00
$ dbh - > do ( $ create . 'longdescs AS SELECT l.comment_id, l.bug_id, u.login_name, l.bug_when, l.thetext, l.work_time FROM longdescs l INNER JOIN ' . $ bugids . ' b ON b.bug_id=l.bug_id INNER JOIN profiles u ON u.userid=l.who' . ( $ userobj - > is_insider ? '' : ' WHERE l.isprivate=0' ) ) ;
$ dbh - > do ( $ create . 'bugs_activity AS SELECT a.id, a.bug_id, u.login_name, a.bug_when, f.name field_name, a.removed, a.added FROM bugs_activity a INNER JOIN ' . $ bugids . ' b ON b.bug_id=a.bug_id INNER JOIN profiles u ON u.userid=a.who INNER JOIN fielddefs f ON f.id=a.fieldid' ) ;
2010-04-27 21:26:52 +04:00
}
}
1 ;
__END__