diff --git a/Bugzilla/DB.pm b/Bugzilla/DB.pm index 9267e8615..6a88c31f2 100644 --- a/Bugzilla/DB.pm +++ b/Bugzilla/DB.pm @@ -300,16 +300,17 @@ sub import { $Exporter::ExportLevel-- if $is_exporter; } -sub sql_istrcmp { +sub sql_istrcmp +{ my ($self, $left, $right, $op) = @_; $op ||= "="; - + return "$left ILIKE $right" if $op eq '='; return $self->sql_istring($left) . " $op " . $self->sql_istring($right); } -sub sql_istring { +sub sql_istring +{ my ($self, $string) = @_; - return "LOWER($string)"; } diff --git a/Bugzilla/DB/Mysql.pm b/Bugzilla/DB/Mysql.pm index f0a095241..e0bc10eb0 100644 --- a/Bugzilla/DB/Mysql.pm +++ b/Bugzilla/DB/Mysql.pm @@ -113,6 +113,13 @@ sub new { return $self; } +sub real_table_list +{ + my $self = shift; + my ($table_like, $table_type) = @_; + return $self->selectcol_arrayref('SHOW TABLES LIKE ?', undef, $table_like); +} + # when last_insert_id() is supported on MySQL by lowest DBI/DBD version # required by Bugzilla, this implementation can be removed. sub bz_last_key { @@ -208,12 +215,20 @@ sub sql_fulltext_search ); } +# Case-insensitive collation is used in MySQL sub sql_istring { my ($self, $string) = @_; return $string; } +# Case-insensitive collation is used in MySQL +sub sql_istrcmp { + my ($self, $a, $b, $op) = @_; + $op ||= "="; + return "$a $op $b"; +} + sub sql_from_days { my ($self, $days) = @_; diff --git a/Bugzilla/DB/Pg.pm b/Bugzilla/DB/Pg.pm index 2068c6981..1dc55d308 100644 --- a/Bugzilla/DB/Pg.pm +++ b/Bugzilla/DB/Pg.pm @@ -196,6 +196,17 @@ sub sql_fulltext_search ); } +sub real_table_list +{ + my $self = shift; + my ($table_like, $table_type) = @_; + return $self->selectcol_arrayref( + 'SELECT table_name FROM information_schema.tables WHERE table_name LIKE ?'. + ' AND table_type=? AND table_catalog=current_database() AND table_schema=current_schema()', + undef, $table_like, lc($table_type) eq 'view' ? 'VIEW' : 'BASE TABLE' + ); +} + # Tell us whether or not a particular sequence exists in the DB. sub bz_sequence_exists { my ($self, $seq_name) = @_; diff --git a/Bugzilla/Search/Saved.pm b/Bugzilla/Search/Saved.pm index 17e2cd8ed..a8f086f61 100644 --- a/Bugzilla/Search/Saved.pm +++ b/Bugzilla/Search/Saved.pm @@ -79,7 +79,7 @@ sub new { {argument => 'name', function => "${class}::new"}); } - my $condition = 'userid = ? AND name = ?'; + my $condition = 'userid = ? AND '.$dbh->sql_istrcmp('name', '?'); my $user_id = blessed $user ? $user->id : $user; detaint_natural($user_id) || ThrowCodeError('param_must_be_numeric', diff --git a/extensions/custis/lib/FlushViews.pm b/extensions/custis/lib/FlushViews.pm index 3ef860fee..d74c2d851 100644 --- a/extensions/custis/lib/FlushViews.pm +++ b/extensions/custis/lib/FlushViews.pm @@ -22,7 +22,7 @@ sub refresh_some_views my ($users) = @_; my %u = ( map { $_ => 1 } @{ $users || [] } ); my $dbh = Bugzilla->dbh; - my $r = $dbh->selectcol_arrayref('SHOW TABLES LIKE \'view$%$bugs\''); + my $r = $dbh->real_table_list('view$%$bugs', 'VIEW'); for (@$r) { my (undef, $user, $query) = split /\$/, $_, -1; @@ -40,15 +40,15 @@ sub refresh_some_views user => $userobj, ) or next; my $sqlquery = $search->getSQL(); - $sqlquery =~ s/ORDER\s+BY\s+`?bugs`?.`?bug_id`?//so; - $dbh->do('DROP VIEW IF EXISTS `view$'.$user.'$'.$query.'$bugs`'); - $dbh->do('DROP VIEW IF EXISTS `view$'.$user.'$'.$query.'$longdescs`'); - $dbh->do('DROP VIEW IF EXISTS `view$'.$user.'$'.$query.'$bugs_activity`'); - $dbh->do('DROP VIEW IF EXISTS `view$'.$user.'$'.$query.'$scrum_cards`'); - $dbh->do('CREATE SQL SECURITY DEFINER VIEW `view$'.$user.'$'.$query.'$bugs` AS '.$sqlquery); - $dbh->do('CREATE SQL SECURITY DEFINER VIEW `view$'.$user.'$'.$query.'$longdescs` AS SELECT l.bug_id, u.login_name, l.bug_when, l.thetext, l.work_time FROM longdescs l INNER JOIN `view$'.$user.'$'.$query.'$bugs` 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 SQL SECURITY DEFINER VIEW `view$'.$user.'$'.$query.'$bugs_activity` AS SELECT a.bug_id, u.login_name, a.bug_when, f.name field_name, a.removed, a.added FROM bugs_activity a INNER JOIN `view$'.$user.'$'.$query.'$bugs` 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'); - $dbh->do('CREATE SQL SECURITY DEFINER VIEW `view$'.$user.'$'.$query.'$scrum_cards` AS SELECT s.* FROM scrum_cards s INNER JOIN `view$'.$user.'$'.$query.'$bugs` b ON b.bug_id=s.bug_id'); + $sqlquery =~ s/ORDER\s+BY\s+bugs.bug_id//so; + $dbh->do('DROP VIEW IF EXISTS view$'.$user.'$'.$query.'$longdescs'); + $dbh->do('DROP VIEW IF EXISTS view$'.$user.'$'.$query.'$bugs_activity'); + $dbh->do('DROP VIEW IF EXISTS view$'.$user.'$'.$query.'$scrum_cards'); + $dbh->do('DROP VIEW IF EXISTS view$'.$user.'$'.$query.'$bugs'); + $dbh->do('CREATE '.($dbh->isa('Bugzilla::DB::Mysql') ? 'SQL SECURITY DEFINER' : '').' VIEW view$'.$user.'$'.$query.'$bugs AS '.$sqlquery); + $dbh->do('CREATE '.($dbh->isa('Bugzilla::DB::Mysql') ? 'SQL SECURITY DEFINER' : '').' VIEW view$'.$user.'$'.$query.'$longdescs AS SELECT l.bug_id, u.login_name, l.bug_when, l.thetext, l.work_time FROM longdescs l INNER JOIN view$'.$user.'$'.$query.'$bugs 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 '.($dbh->isa('Bugzilla::DB::Mysql') ? 'SQL SECURITY DEFINER' : '').' VIEW view$'.$user.'$'.$query.'$bugs_activity AS SELECT a.bug_id, u.login_name, a.bug_when, f.name field_name, a.removed, a.added FROM bugs_activity a INNER JOIN view$'.$user.'$'.$query.'$bugs 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'); + $dbh->do('CREATE '.($dbh->isa('Bugzilla::DB::Mysql') ? 'SQL SECURITY DEFINER' : '').' VIEW view$'.$user.'$'.$query.'$scrum_cards AS SELECT s.* FROM scrum_cards s INNER JOIN view$'.$user.'$'.$query.'$bugs b ON b.bug_id=s.bug_id'); } }