Commit 793c1035 authored by mkanat%bugzilla.org's avatar mkanat%bugzilla.org

Bug 408172: [Oracle] Bug lists longer than 1000 bugs fail

Patch By Xiaoou Wu <xiaoou.wu@oracle.com> r=mkanat, a=mkanat
parent 2c8316b9
...@@ -99,13 +99,14 @@ sub _retrieve { ...@@ -99,13 +99,14 @@ sub _retrieve {
'attachments.isprivate AS isprivate' 'attachments.isprivate AS isprivate'
); );
my $columns = join(", ", @columns); my $columns = join(", ", @columns);
my $dbh = Bugzilla->dbh;
my $records = Bugzilla->dbh->selectall_arrayref("SELECT $columns my $records = $dbh->selectall_arrayref(
FROM attachments "SELECT $columns
WHERE attach_id IN (" . FROM attachments
join(",", @$ids) . ") WHERE "
ORDER BY attach_id", . Bugzilla->dbh->sql_in('attach_id', $ids)
{ Slice => {} }); . " ORDER BY attach_id",
{ Slice => {} });
return $records; return $records;
} }
......
...@@ -635,8 +635,8 @@ sub update_cc { ...@@ -635,8 +635,8 @@ sub update_cc {
my ($removed, $added) = diff_arrays(\@old_cc, \@new_cc); my ($removed, $added) = diff_arrays(\@old_cc, \@new_cc);
if (scalar @$removed) { if (scalar @$removed) {
$dbh->do('DELETE FROM cc WHERE bug_id = ? AND who IN (' . $dbh->do('DELETE FROM cc WHERE bug_id = ? AND '
join(',', @$removed) . ')', undef, $self->id); . $dbh->sql_in('who', $removed), undef, $self->id);
} }
foreach my $user_id (@$added) { foreach my $user_id (@$added) {
$dbh->do('INSERT INTO cc (bug_id, who) VALUES (?,?)', $dbh->do('INSERT INTO cc (bug_id, who) VALUES (?,?)',
...@@ -722,8 +722,8 @@ sub update_keywords { ...@@ -722,8 +722,8 @@ sub update_keywords {
my ($removed, $added) = diff_arrays(\@old_ids, \@new_ids); my ($removed, $added) = diff_arrays(\@old_ids, \@new_ids);
if (scalar @$removed) { if (scalar @$removed) {
$dbh->do('DELETE FROM keywords WHERE bug_id = ? AND keywordid IN (' $dbh->do('DELETE FROM keywords WHERE bug_id = ? AND '
. join(',', @$removed) . ')', undef, $self->id); . $dbh->sql_in('keywordid', $removed), undef, $self->id);
} }
foreach my $keyword_id (@$added) { foreach my $keyword_id (@$added) {
$dbh->do('INSERT INTO keywords (bug_id, keywordid) VALUES (?,?)', $dbh->do('INSERT INTO keywords (bug_id, keywordid) VALUES (?,?)',
...@@ -798,8 +798,8 @@ sub remove_from_db { ...@@ -798,8 +798,8 @@ sub remove_from_db {
WHERE bug_id = ?", undef, $bug_id); WHERE bug_id = ?", undef, $bug_id);
if (scalar(@$attach_ids)) { if (scalar(@$attach_ids)) {
$dbh->do("DELETE FROM attach_data WHERE id IN (" . $dbh->do("DELETE FROM attach_data WHERE "
join(",", @$attach_ids) . ")"); . $dbh->sql_in('id', $attach_ids));
} }
# Several of the previous tables also depend on attach_id. # Several of the previous tables also depend on attach_id.
...@@ -3018,7 +3018,7 @@ sub CountOpenDependencies { ...@@ -3018,7 +3018,7 @@ sub CountOpenDependencies {
my $sth = $dbh->prepare( my $sth = $dbh->prepare(
"SELECT blocked, COUNT(bug_status) " . "SELECT blocked, COUNT(bug_status) " .
"FROM bugs, dependencies " . "FROM bugs, dependencies " .
"WHERE blocked IN (" . (join "," , @bug_list) . ") " . "WHERE " . $dbh->sql_in('blocked', \@bug_list) .
"AND bug_id = dependson " . "AND bug_id = dependson " .
"AND bug_status IN (" . join(', ', map {$dbh->quote($_)} BUG_STATE_OPEN) . ") " . "AND bug_status IN (" . join(', ', map {$dbh->quote($_)} BUG_STATE_OPEN) . ") " .
$dbh->sql_group_by('blocked')); $dbh->sql_group_by('blocked'));
......
...@@ -391,6 +391,11 @@ sub sql_string_concat { ...@@ -391,6 +391,11 @@ sub sql_string_concat {
return '(' . join(' || ', @params) . ')'; return '(' . join(' || ', @params) . ')';
} }
sub sql_in {
my ($self, $column_name, $in_list_ref) = @_;
return " $column_name IN (" . join(',', @$in_list_ref) . ") ";
}
sub sql_fulltext_search { sub sql_fulltext_search {
my ($self, $column, $text) = @_; my ($self, $column, $text) = @_;
...@@ -1918,6 +1923,32 @@ will not be usually used unless it was created as LOWER(column). ...@@ -1918,6 +1923,32 @@ will not be usually used unless it was created as LOWER(column).
=back =back
=item C<sql_in>
=over
=item B<Description>
Returns SQL syntax for the C<IN ()> operator.
Only necessary where an C<IN> clause can have more than 1000 items.
=item B<Params>
=over
=item C<$column_name> - Column name (e.g. C<bug_id>)
=item C<$in_list_ref> - an arrayref containing values for C<IN ()>
=back
=item B<Returns>
Formatted SQL for the C<IN> operator.
=back
=item C<bz_lock_tables> =item C<bz_lock_tables>
=over =over
......
...@@ -165,6 +165,22 @@ sub sql_position { ...@@ -165,6 +165,22 @@ sub sql_position {
my ($self, $fragment, $text) = @_; my ($self, $fragment, $text) = @_;
return "INSTR($text, $fragment)"; return "INSTR($text, $fragment)";
} }
sub sql_in {
my ($self, $column_name, $in_list_ref) = @_;
my @in_list = @$in_list_ref;
return $self->SUPER::sql_in($column_name, $in_list_ref) if $#in_list < 1000;
my @in_str;
while (@in_list) {
my $length = $#in_list + 1;
my $splice = $length > 1000 ? 1000 : $length;
my @sub_in_list = splice(@in_list, 0, $splice);
push(@in_str,
$self->SUPER::sql_in($column_name, \@sub_in_list));
}
return "( " . join(" OR ", @in_str) . " )";
}
sub _fix_empty { sub _fix_empty {
my ($string) = @_; my ($string) = @_;
$string = '' if $string eq EMPTY_STRING; $string = '' if $string eq EMPTY_STRING;
......
...@@ -295,11 +295,12 @@ sub validate { ...@@ -295,11 +295,12 @@ sub validate {
my $not = ($attach_id) ? "" : "NOT"; my $not = ($attach_id) ? "" : "NOT";
my $invalid_data = my $invalid_data =
$dbh->selectrow_array("SELECT 1 FROM flags $dbh->selectrow_array(
WHERE id IN (" . join(',', @flag_ids) . ") "SELECT 1 FROM flags
AND ($field != ? OR attach_id IS $not NULL) " . WHERE "
$dbh->sql_limit(1), . $dbh->sql_in('id', \@flag_ids)
undef, $field_id); . " AND ($field != ? OR attach_id IS $not NULL) "
. $dbh->sql_limit(1), undef, $field_id);
if ($invalid_data) { if ($invalid_data) {
ThrowCodeError('invalid_flag_association', ThrowCodeError('invalid_flag_association',
......
...@@ -144,7 +144,7 @@ sub remove_from_db { ...@@ -144,7 +144,7 @@ sub remove_from_db {
my $timestamp = $dbh->selectrow_array('SELECT NOW()'); my $timestamp = $dbh->selectrow_array('SELECT NOW()');
$dbh->do('UPDATE bugs SET target_milestone = ?, delta_ts = ? $dbh->do('UPDATE bugs SET target_milestone = ?, delta_ts = ?
WHERE bug_id IN (' . join(', ', @$bug_ids) . ')', WHERE ' . $dbh->sql_in('bug_id', $bug_ids),
undef, ($self->product->default_milestone, $timestamp)); undef, ($self->product->default_milestone, $timestamp));
require Bugzilla::Bug; require Bugzilla::Bug;
......
...@@ -145,8 +145,9 @@ sub new_from_list { ...@@ -145,8 +145,9 @@ sub new_from_list {
push(@detainted_ids, $id); push(@detainted_ids, $id);
} }
$objects = $dbh->selectall_arrayref( $objects = $dbh->selectall_arrayref(
"SELECT $columns FROM $table WHERE $id_field IN (" "SELECT $columns FROM $table WHERE "
. join(',', @detainted_ids) . ") ORDER BY $order", {Slice=>{}}); . $dbh->sql_in($id_field, \@detainted_ids)
. "ORDER BY $order", {Slice=>{}});
} else { } else {
return []; return [];
} }
......
...@@ -352,8 +352,8 @@ sub init { ...@@ -352,8 +352,8 @@ sub init {
$extra .= " AND actcheck.added = $sql_chvalue"; $extra .= " AND actcheck.added = $sql_chvalue";
} }
push(@supptables, "LEFT JOIN bugs_activity AS actcheck " . push(@supptables, "LEFT JOIN bugs_activity AS actcheck " .
"ON $extra AND actcheck.fieldid IN (" . "ON $extra AND "
join(",", @actlist) . ")"); . $dbh->sql_in('actcheck.fieldid', \@actlist));
} }
# Now that we're done using @list to determine if there are any # Now that we're done using @list to determine if there are any
...@@ -1082,7 +1082,7 @@ sub init { ...@@ -1082,7 +1082,7 @@ sub init {
push(@list, $q); push(@list, $q);
} }
if (@list) { if (@list) {
$term = "$ff IN (" . join (',', @list) . ")"; $term = $dbh->sql_in($ff, \@list);
} }
}, },
",anywordssubstr" => sub { ",anywordssubstr" => sub {
...@@ -1519,7 +1519,7 @@ sub build_subselect { ...@@ -1519,7 +1519,7 @@ sub build_subselect {
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
my $list = $dbh->selectcol_arrayref($q); my $list = $dbh->selectcol_arrayref($q);
return "1=2" unless @$list; # Could use boolean type on dbs which support it return "1=2" unless @$list; # Could use boolean type on dbs which support it
return "$outer IN (" . join(',', @$list) . ")"; return $dbh->sql_in($outer, $list);
} }
sub GetByWordList { sub GetByWordList {
......
...@@ -1084,7 +1084,7 @@ if (@bugidlist) { ...@@ -1084,7 +1084,7 @@ if (@bugidlist) {
"LEFT JOIN group_control_map " . "LEFT JOIN group_control_map " .
"ON group_control_map.product_id = bugs.product_id " . "ON group_control_map.product_id = bugs.product_id " .
"AND group_control_map.group_id = bug_group_map.group_id " . "AND group_control_map.group_id = bug_group_map.group_id " .
"WHERE bugs.bug_id IN (" . join(',',@bugidlist) . ") " . "WHERE " . $dbh->sql_in('bugs.bug_id', \@bugidlist) .
$dbh->sql_group_by('bugs.bug_id')); $dbh->sql_group_by('bugs.bug_id'));
$sth->execute(); $sth->execute();
while (my ($bug_id, $min_membercontrol) = $sth->fetchrow_array()) { while (my ($bug_id, $min_membercontrol) = $sth->fetchrow_array()) {
...@@ -1161,19 +1161,23 @@ if ($dotweak) { ...@@ -1161,19 +1161,23 @@ if ($dotweak) {
my @bug_statuses = map {$dbh->quote($_)} keys %$bugstatuses; my @bug_statuses = map {$dbh->quote($_)} keys %$bugstatuses;
my $bug_status_ids = my $bug_status_ids =
$dbh->selectcol_arrayref('SELECT id FROM bug_status $dbh->selectcol_arrayref('SELECT id FROM bug_status
WHERE value IN (' . join(', ', @bug_statuses) .')'); WHERE ' . $dbh->sql_in('value', \@bug_statuses));
# This query collects new statuses which are common to all current bug statuses. # This query collects new statuses which are common to all current bug statuses.
# It also accepts transitions where the bug status doesn't change. # It also accepts transitions where the bug status doesn't change.
$bug_status_ids = $bug_status_ids =
$dbh->selectcol_arrayref('SELECT DISTINCT new_status $dbh->selectcol_arrayref(
FROM status_workflow sw1 'SELECT DISTINCT new_status
WHERE NOT EXISTS (SELECT * FROM status_workflow sw2 FROM status_workflow sw1
WHERE sw2.old_status != sw1.new_status WHERE NOT EXISTS
AND sw2.old_status IN (' . join(', ', @$bug_status_ids) . ') (SELECT * FROM status_workflow sw2
AND NOT EXISTS (SELECT * FROM status_workflow sw3 WHERE sw2.old_status != sw1.new_status
WHERE sw3.new_status = sw1.new_status AND '
AND sw3.old_status = sw2.old_status))'); . $dbh->sql_in('sw2.old_status', $bug_status_ids)
. ' AND NOT EXISTS
(SELECT * FROM status_workflow sw3
WHERE sw3.new_status = sw1.new_status
AND sw3.old_status = sw2.old_status))');
$vars->{'current_bug_statuses'} = [keys %$bugstatuses]; $vars->{'current_bug_statuses'} = [keys %$bugstatuses];
$vars->{'new_bug_statuses'} = Bugzilla::Status->new_from_list($bug_status_ids); $vars->{'new_bug_statuses'} = Bugzilla::Status->new_from_list($bug_status_ids);
......
...@@ -327,11 +327,9 @@ if ($cgi->param('product') ne $cgi->param('dontchange')) { ...@@ -327,11 +327,9 @@ if ($cgi->param('product') ne $cgi->param('dontchange')) {
$product = Bugzilla::Product::check_product(scalar $cgi->param('product')); $product = Bugzilla::Product::check_product(scalar $cgi->param('product'));
@newprod_ids = ($product->id); @newprod_ids = ($product->id);
} else { } else {
@newprod_ids = @{$dbh->selectcol_arrayref("SELECT DISTINCT product_id @newprod_ids = @{$dbh->selectcol_arrayref(
FROM bugs "SELECT DISTINCT product_id FROM bugs WHERE "
WHERE bug_id IN (" . . $dbh->sql_in('bug_id', \@idlist))};
join(',', @idlist) .
")")};
if (scalar(@newprod_ids) == 1) { if (scalar(@newprod_ids) == 1) {
$product = new Bugzilla::Product($newprod_ids[0]); $product = new Bugzilla::Product($newprod_ids[0]);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment