summaryrefslogtreecommitdiffstats
path: root/buglist.cgi
diff options
context:
space:
mode:
authorterry%mozilla.org <>2000-01-28 10:01:36 +0100
committerterry%mozilla.org <>2000-01-28 10:01:36 +0100
commit8fdb0d3601e63fb8a07bff32945fb5d84fbd4678 (patch)
treedbed4ea3cefbe7b317f3f997860e12528499eb0a /buglist.cgi
parentb23cb23b54adf11260e69dbc0c6294702ea42159 (diff)
downloadbugzilla-8fdb0d3601e63fb8a07bff32945fb5d84fbd4678.tar.gz
bugzilla-8fdb0d3601e63fb8a07bff32945fb5d84fbd4678.tar.xz
Massive stomp on the query page and buglist page. Added the ability
to use the "boolean charts" to do very powerful queries.
Diffstat (limited to 'buglist.cgi')
-rwxr-xr-xbuglist.cgi928
1 files changed, 567 insertions, 361 deletions
diff --git a/buglist.cgi b/buglist.cgi
index 5cae83b87..902d09f12 100755
--- a/buglist.cgi
+++ b/buglist.cgi
@@ -46,17 +46,565 @@ sub sillyness {
$zz = @::versions;
};
-
+my $serverpush = 0;
ConnectToDatabase();
# print "Content-type: text/plain\n\n"; # Handy for debugging.
+# $::FORM{'debug'} = 1;
+
+
+if (grep(/^cmd-/, keys(%::FORM))) {
+ my $url = "query.cgi#chart?$::buffer";
+ print qq{Refresh: 0; URL=$url
+Content-type: text/html
+
+<A HREF="$url">Adding field to query page...</A>
+};
+ exit();
+}
+
+
if (!defined $::FORM{'cmdtype'}) {
# This can happen if there's an old bookmark to a query...
$::FORM{'cmdtype'} = 'doit';
}
+
+sub SqlifyDate {
+ my ($str) = (@_);
+ if (!defined $str) {
+ $str = "";
+ }
+ my $date = str2time($str);
+ if (!defined $date) {
+ print "\n\n<P>The string '<tt>$str</tt>' is not a legal date.\n";
+ print "<P>Please click the <B>Back</B> button and try again.\n";
+ PutFooter();
+ exit;
+ }
+ return time2str("%Y/%m/%d %H:%M:%S", $date);
+}
+
+
+sub GetByWordList {
+ my ($field, $strs) = (@_);
+ my @list;
+
+ foreach my $w (split(/[\s,]+/, $strs)) {
+ my $word = $w;
+ if ($word ne "") {
+ $word =~ tr/A-Z/a-z/;
+ $word = SqlQuote(quotemeta($word));
+ $word =~ s/^'//;
+ $word =~ s/'$//;
+ $word = '(^|[^a-z0-9])' . $word . '($|[^a-z0-9])';
+ push(@list, "lower($field) regexp '$word'");
+ }
+ }
+
+ return \@list;
+}
+
+
+
+sub Error {
+ my ($str) = (@_);
+ if (!$serverpush) {
+ print "Content-type: text/html\n\n";
+ }
+ print $str;
+ print "\n<P>Please press <B>Back</B> and try again.\n";
+ PutFooter();
+ exit();
+}
+
+
+
+
+
+sub GenerateSQL {
+ my $debug = 0;
+ my ($fieldsref, $supptablesref, $wherepartref, $urlstr) = (@_);
+ my @fields;
+ my @supptables;
+ my @wherepart;
+ @fields = @$fieldsref if $fieldsref;
+ @supptables = @$supptablesref if $supptablesref;
+ @wherepart = @$wherepartref if $wherepartref;
+ my %F;
+ my %M;
+ ParseUrlString($urlstr, \%F, \%M);
+ my @specialchart;
+ my @andlist;
+
+ # First, deal with all the old hard-coded non-chart-based poop.
+
+ unshift(@supptables,
+ ("profiles map_assigned_to",
+ "profiles map_reporter",
+ "LEFT JOIN profiles map_qa_contact ON bugs.qa_contact = map_qa_contact.userid"));
+ unshift(@wherepart,
+ ("bugs.assigned_to = map_assigned_to.userid",
+ "bugs.reporter = map_reporter.userid",
+ "bugs.groupset & $::usergroupset = bugs.groupset"));
+
+
+ my $minvotes;
+ if (defined $F{'votes'}) {
+ my $c = trim($F{'votes'});
+ if ($c ne "") {
+ if ($c !~ /^[0-9]*$/) {
+ return Error("The 'At least ___ votes' field must be a\n" .
+ "simple number. You entered \"$c\", which\n" .
+ "doesn't cut it.");
+ }
+ push(@specialchart, ["votes", "greaterthan", $c - 1]);
+ }
+ }
+
+ if ($M{'bug_id'}) {
+ my $type = "anyexact";
+ if ($F{'bugidtype'} && $F{'bugidtype'} eq 'exclude') {
+ $type = "noexact";
+ }
+ push(@specialchart, ["bug_id", $type, join(',', @{$M{'bug_id'}})]);
+ }
+
+ if (defined $F{'sql'}) {
+ push(@wherepart, "( $F{'sql'} )");
+ }
+
+ my @legal_fields = ("product", "version", "rep_platform", "op_sys",
+ "bug_status", "resolution", "priority", "bug_severity",
+ "assigned_to", "reporter", "component",
+ "target_milestone", "groupset");
+
+ foreach my $field (keys %F) {
+ if (lsearch(\@legal_fields, $field) != -1) {
+ push(@specialchart, [$field, "anyexact",
+ join(',', @{$M{$field}})]);
+ }
+ }
+
+ if ($F{'keywords'}) {
+ my $t = $F{'keywords_type'};
+ if (!$t || $t eq "or") {
+ $t = "anywords";
+ }
+ push(@specialchart, ["keywords", $t, $F{'keywords'}]);
+ }
+
+ foreach my $id ("1", "2") {
+ if (!defined ($F{"email$id"})) {
+ next;
+ }
+ my $email = trim($F{"email$id"});
+ if ($email eq "") {
+ next;
+ }
+ my $type = $F{"emailtype$id"};
+ if ($type eq "exact") {
+ $type = "anyexact";
+ foreach my $name (split(',', $email)) {
+ $name = trim($name);
+ if ($name) {
+ DBNameToIdAndCheck($name);
+ }
+ }
+ }
+
+ my @clist;
+ foreach my $field ("assigned_to", "reporter", "cc", "qa_contact") {
+ if ($F{"email$field$id"}) {
+ push(@clist, $field, $type, $email);
+ }
+ }
+ if ($F{"emaillongdesc$id"}) {
+ my $table = "longdescs_";
+ push(@supptables, "longdescs $table");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ my $ptable = "longdescnames_";
+ push(@supptables,
+ "LEFT JOIN profiles $ptable ON $table.who = $ptable.userid");
+ push(@clist, "$ptable.login_name", $type, $email);
+ }
+ if (@clist) {
+ push(@specialchart, \@clist);
+ } else {
+ return Error("You must specify one or more fields in which to\n" .
+ "search for <tt>$email</tt>.\n");
+ }
+ }
+
+
+ if (defined $F{'changedin'}) {
+ my $c = trim($F{'changedin'});
+ if ($c ne "") {
+ if ($c !~ /^[0-9]*$/) {
+ return Error("The 'changed in last ___ days' field must be\n" .
+ "a simple number. You entered \"$c\", which\n" .
+ "doesn't cut it.");
+ }
+ push(@specialchart, ["changedin",
+ "lessthan", $c + 1]);
+ }
+ }
+
+ my $ref = $M{'chfield'};
+
+ if (defined $ref) {
+ my $which = lsearch($ref, "[Bug creation]");
+ if ($which >= 0) {
+ splice(@$ref, $which, 1);
+ push(@specialchart, ["creation_ts", "greaterthan",
+ SqlifyDate($F{'chfieldfrom'})]);
+ my $to = $F{'chfieldto'};
+ if (defined $to) {
+ $to = trim($to);
+ if ($to ne "" && $to !~ /^now$/i) {
+ push(@specialchart, ["creation_ts", "lessthan",
+ SqlifyDate($to)]);
+ }
+ }
+ }
+ }
+
+
+
+ if (defined $ref && 0 < @$ref) {
+ push(@supptables, "bugs_activity actcheck");
+
+ my @list;
+ foreach my $f (@$ref) {
+ push(@list, "\nactcheck.fieldid = " . GetFieldID($f));
+ }
+ push(@wherepart, "actcheck.bug_id = bugs.bug_id");
+ push(@wherepart, "(" . join(' OR ', @list) . ")");
+ push(@wherepart, "actcheck.bug_when >= " .
+ SqlQuote(SqlifyDate($F{'chfieldfrom'})));
+ my $to = $F{'chfieldto'};
+ if (defined $to) {
+ $to = trim($to);
+ if ($to ne "" && $to !~ /^now$/i) {
+ push(@wherepart, "actcheck.bug_when <= " .
+ SqlQuote(SqlifyDate($to)));
+ }
+ }
+ my $value = $F{'chfieldvalue'};
+ if (defined $value) {
+ $value = trim($value);
+ if ($value ne "") {
+ push(@wherepart, "actcheck.newvalue = " .
+ SqlQuote($value))
+ }
+ }
+ }
+
+
+ foreach my $f ("short_desc", "long_desc", "bug_file_loc",
+ "status_whiteboard") {
+ if (defined $F{$f}) {
+ my $s = trim($F{$f});
+ if ($s ne "") {
+ my $n = $f;
+ my $q = SqlQuote($s);
+ my $type = $F{$f . "_type"};
+ push(@specialchart, [$f, $type, $s]);
+ }
+ }
+ }
+
+
+ my $chartid;
+ my $f;
+ my $t;
+ my $q;
+ my $v;
+ my $term;
+ my %funcsbykey;
+ my @funcdefs =
+ (
+ "^(assigned_to|reporter)," => sub {
+ push(@supptables, "profiles map_$f");
+ push(@wherepart, "bugs.$f = map_$f.userid");
+ $f = "map_$f.login_name";
+ },
+ "^qa_contact," => sub {
+ push(@supptables,
+ "LEFT JOIN profiles map_qa_contact ON bugs.qa_contact = map_qa_contact.userid");
+ $f = "map_$f.login_name";
+ },
+ "^cc," => sub {
+ push(@supptables,
+ ("LEFT JOIN cc cc_$chartid ON bugs.bug_id = cc_$chartid.bug_id LEFT JOIN profiles map_cc_$chartid ON cc_$chartid.who = map_cc_$chartid.userid"));
+ $f = "map_cc_$chartid.login_name";
+ },
+ "^long_?desc,changedby" => sub {
+ my $table = "longdescs_$chartid";
+ push(@supptables, "longdescs $table");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ my $id = DBNameToIdAndCheck($v);
+ $term = "$table.who = $id";
+ },
+ "^long_?desc,changedbefore" => sub {
+ my $table = "longdescs_$chartid";
+ push(@supptables, "longdescs $table");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ $term = "$table.who < " . SqlQuote(SqlifyDate($v));
+ },
+ "^long_?desc,changedafter" => sub {
+ my $table = "longdescs_$chartid";
+ push(@supptables, "longdescs $table");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ $term = "$table.who > " . SqlQuote(SqlifyDate($v));
+ },
+ "^long_?desc," => sub {
+ my $table = "longdescs_$chartid";
+ push(@supptables, "longdescs $table");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ $f = "$table.thetext";
+ },
+ "^changedin," => sub {
+ $f = "(to_days(now()) - to_days(bugs.delta_ts))";
+ },
+
+ "^keywords," => sub {
+ GetVersionTable();
+ my @list;
+ my $table = "keywords_$chartid";
+ foreach my $value (split(/[\s,]+/, $v)) {
+ if ($value eq '') {
+ next;
+ }
+ my $id = $::keywordsbyname{$value};
+ if ($id) {
+ push(@list, "$table.keywordid = $id");
+ } else {
+ return Error("Unknown keyword named <code>$v</code>.\n" .
+ "<P>The legal keyword names are\n" .
+ "<A HREF=describekeywords.cgi>" .
+ "listed here</A>.\n");
+ }
+ }
+ my $haveawordterm;
+ if (@list) {
+ $haveawordterm = "(" . join(' OR ', @list) . ")";
+ if ($t eq "anywords") {
+ $term = $haveawordterm;
+ } elsif ($t eq "allwords") {
+ $ref = $funcsbykey{",$t"};
+ &$ref;
+ if ($term && $haveawordterm) {
+ $term = "(($term) AND $haveawordterm)";
+ }
+ }
+ }
+ if ($term) {
+ push(@supptables, "keywords $table");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ }
+ },
+
+
+ ",equals" => sub {
+ $term = "$f = $q";
+ },
+ ",notequals" => sub {
+ $term = "$f != $q";
+ },
+ ",casesubstring" => sub {
+ $term = "INSTR($f, $q)";
+ },
+ ",(substring|substr)" => sub {
+ $term = "INSTR(LOWER($f), " . lc($q) . ")";
+ },
+ ",notsubstring" => sub {
+ $term = "INSTR(LOWER($f), " . lc($q) . ") = 0";
+ },
+ ",regexp" => sub {
+ $term = "LOWER($f) REGEXP $q";
+ },
+ ",notregexp" => sub {
+ $term = "LOWER($f) NOT REGEXP $q";
+ },
+ ",lessthan" => sub {
+ $term = "$f < $q";
+ },
+ ",greaterthan" => sub {
+ $term = "$f > $q";
+ },
+ ",anyexact" => sub {
+ my @list;
+ foreach my $w (split(/,/, $v)) {
+ if ($w eq "---") {
+ $w = "";
+ }
+ push(@list, "$f = " . SqlQuote($w));
+ }
+ $term = join(" OR ", @list);
+ },
+ ",anywords" => sub {
+ $term = join(" OR ", @{GetByWordList($f, $v)});
+ },
+ ",allwords" => sub {
+ $term = join(" AND ", @{GetByWordList($f, $v)});
+ },
+ ",nowords" => sub {
+ my @list = @{GetByWordList($f, $v)};
+ if (@list) {
+ $term = "NOT (" . join(" OR ", @list) . ")";
+ }
+ },
+ ",changedbefore" => sub {
+ my $table = "act_$chartid";
+ my $ftable = "fielddefs_$chartid";
+ push(@supptables, "bugs_activity $table");
+ push(@supptables, "fielddefs $ftable");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ push(@wherepart, "$table.fieldid = $ftable.fieldid");
+ $term = "($ftable.name = '$f' AND $table.bug_when < $q)";
+ },
+ ",changedafter" => sub {
+ my $table = "act_$chartid";
+ my $ftable = "fielddefs_$chartid";
+ push(@supptables, "bugs_activity $table");
+ push(@supptables, "fielddefs $ftable");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ push(@wherepart, "$table.fieldid = $ftable.fieldid");
+ $term = "($ftable.name = '$f' AND $table.bug_when > $q)";
+ },
+ ",changedto" => sub {
+ my $table = "act_$chartid";
+ my $ftable = "fielddefs_$chartid";
+ push(@supptables, "bugs_activity $table");
+ push(@supptables, "fielddefs $ftable");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ push(@wherepart, "$table.fieldid = $ftable.fieldid");
+ $term = "($ftable.name = '$f' AND $table.newvalue = $q)";
+ },
+ ",changedby" => sub {
+ my $table = "act_$chartid";
+ my $ftable = "fielddefs_$chartid";
+ push(@supptables, "bugs_activity $table");
+ push(@supptables, "fielddefs $ftable");
+ push(@wherepart, "$table.bug_id = bugs.bug_id");
+ push(@wherepart, "$table.fieldid = $ftable.fieldid");
+ my $id = DBNameToIdAndCheck($v);
+ $term = "($ftable.name = '$f' AND $table.who = $id)";
+ },
+ );
+ my @funcnames;
+ while (@funcdefs) {
+ my $key = shift(@funcdefs);
+ my $value = shift(@funcdefs);
+ if ($key =~ /^[^,]*$/) {
+ die "All defs in %funcs must have a comma in their name: $key";
+ }
+ if (exists $funcsbykey{$key}) {
+ die "Duplicate key in %funcs: $key";
+ }
+ $funcsbykey{$key} = $value;
+ push(@funcnames, $key);
+ }
+
+
+ my $chart = -1;
+ my $row = 0;
+ foreach my $ref (@specialchart) {
+ my $col = 0;
+ while (@$ref) {
+ $F{"field$chart-$row-$col"} = shift(@$ref);
+ $F{"type$chart-$row-$col"} = shift(@$ref);
+ $F{"value$chart-$row-$col"} = shift(@$ref);
+ if ($debug) {
+ print qq{<P>$F{"field$chart-$row-$col"} | $F{"type$chart-$row-$col"} | $F{"value$chart-$row-$col"}*\n};
+ }
+ $col++;
+
+ }
+ $row++;
+ }
+
+
+ for ($chart=-1 ;
+ $chart < 0 || exists $F{"field$chart-0-0"} ;
+ $chart++) {
+ $chartid = $chart >= 0 ? $chart : "";
+ for (my $row = 0 ;
+ exists $F{"field$chart-$row-0"} ;
+ $row++) {
+ my @orlist;
+ for (my $col = 0 ;
+ exists $F{"field$chart-$row-$col"} ;
+ $col++) {
+ $f = $F{"field$chart-$row-$col"} || "noop";
+ $t = $F{"type$chart-$row-$col"} || "noop";
+ $v = $F{"value$chart-$row-$col"};
+ $v = "" if !defined $v;
+ $v = trim($v);
+ if ($f eq "noop" || $t eq "noop" || $v eq "") {
+ next;
+ }
+ $q = SqlQuote($v);
+ my $func;
+ $term = undef;
+ foreach my $key (@funcnames) {
+ if ("$f,$t" =~ m/$key/) {
+ my $ref = $funcsbykey{$key};
+ if ($debug) {
+ print "<P>$key ($f , $t ) => ";
+ }
+ &$ref;
+ if ($debug) {
+ print "$f , $t , $term";
+ }
+ if ($term) {
+ last;
+ }
+ }
+ }
+ if ($term) {
+ push(@orlist, $term);
+ } else {
+ my $errstr = "Can't seem to handle " .
+ qq{'<code>$F{"field$chart-$row-$col"}</code>' and } .
+ qq{'<code>$F{"type$chart-$row-$col"}</code>' } .
+ "together";
+ die "Internal error: $errstr" if $chart < 0;
+ return Error($errstr);
+ }
+ }
+ if (@orlist) {
+ push(@andlist, "(" . join(" OR ", @orlist) . ")");
+ }
+ }
+ }
+ my %suppseen = ("bugs" => 1);
+ my $suppstring = "bugs";
+ foreach my $str (@supptables) {
+ if (!$suppseen{$str}) {
+ if ($str !~ /^LEFT JOIN/i) {
+ $suppstring .= ",";
+ }
+ $suppstring .= " $str";
+ $suppseen{$str} = 1;
+ }
+ }
+ my $query = ("SELECT " . join(', ', @fields) .
+ " FROM $suppstring" .
+ " WHERE " . join(' AND ', (@wherepart, @andlist)) .
+ " GROUP BY bugs.bug_id");
+ if ($debug) {
+ print "<P><CODE>" . value_quote($query) . "</CODE><P>\n";
+ exit();
+ }
+ return $query;
+}
+
+
+
sub LookupNamedQuery {
my ($name) = (@_);
confirm_login();
@@ -164,7 +712,6 @@ OK, you have a new query named <code>$name</code>
}
-my $serverpush = 0;
if ($ENV{'HTTP_USER_AGENT'} =~ /Mozilla.[3-9]/ && $ENV{'HTTP_USER_AGENT'} !~ /[Cc]ompatible/ ) {
# Search for real Netscape 3 and up. http://www.browsercaps.org used as source of
# browsers compatbile with server-push. It's a Netscape hack, incompatbile
@@ -205,9 +752,11 @@ DefCol("severity", "substring(bugs.bug_severity, 1, 3)", "Sev",
DefCol("priority", "substring(bugs.priority, 1, 3)", "Pri", "bugs.priority");
DefCol("platform", "substring(bugs.rep_platform, 1, 3)", "Plt",
"bugs.rep_platform");
-DefCol("owner", "assign.login_name", "Owner", "assign.login_name");
-DefCol("reporter", "report.login_name", "Reporter", "report.login_name");
-DefCol("qa_contact", "qacont.login_name", "QAContact", "qacont.login_name");
+DefCol("owner", "map_assigned_to.login_name", "Owner",
+ "map_assigned_to.login_name");
+DefCol("reporter", "map_reporter.login_name", "Reporter",
+ "map_reporter.login_name");
+DefCol("qa_contact", "map_qa_contact.login_name", "QAContact", "map_qa_contact.login_name");
DefCol("status", "substring(bugs.bug_status,1,4)", "State", "bugs.bug_status");
DefCol("resolution", "substring(bugs.resolution,1,4)", "Result",
"bugs.resolution");
@@ -233,16 +782,7 @@ if (defined $::COOKIE{'COLUMNLIST'}) {
my $minvotes;
if (defined $::FORM{'votes'}) {
- my $c = trim($::FORM{'votes'});
- if ($c ne "") {
- if ($c !~ /^[0-9]*$/) {
- print "\n\n<P>The 'At least ___ votes' field must be a simple ";
- print "number. You entered \"$c\", which doesn't cut it.";
- print "<P>Please click the <B>Back</B> button and try again.\n";
- PutFooter();
- exit;
- }
- $minvotes = $c;
+ if (trim($::FORM{'votes'}) ne "") {
if (! (grep {/^votes$/} @collist)) {
push(@collist, 'votes');
}
@@ -259,36 +799,20 @@ if ($dotweak) {
}
-my $query = "select bugs.bug_id, bugs.groupset";
+my @fields = ("bugs.bug_id", "bugs.groupset");
foreach my $c (@collist) {
if (exists $::needquote{$c}) {
- $query .= ",
-\t$::key{$c}";
+ push(@fields, "$::key{$c}");
}
}
if ($dotweak) {
- $query .= ",
-bugs.product,
-bugs.bug_status";
+ push(@fields, "bugs.product", "bugs.bug_status");
}
-$query .= "
-from bugs,
- profiles assign,
- profiles report
- left join profiles qacont on bugs.qa_contact = qacont.userid,
- versions projector
-
-where bugs.assigned_to = assign.userid
-and bugs.reporter = report.userid
-and bugs.product = projector.program
-and bugs.version = projector.value
-and bugs.groupset & $::usergroupset = bugs.groupset
-";
if ($::FORM{'regetlastlist'}) {
if (!$::COOKIE{'BUGLIST'}) {
@@ -309,331 +833,10 @@ query. You will have to start over at the <A HREF="query.cgi">query page</A>.
url_quote($::FORM{'order'});
}
-if ((defined $::FORM{'emailcc1'} && $::FORM{'emailcc1'}) ||
- (defined $::FORM{'emailcc2'} && $::FORM{'emailcc2'})) {
-
- # We need to poke into the CC table. Do weird SQL left join stuff so that
- # we can look in the CC table, but won't reject any bugs that don't have
- # any CC fields.
- $query =~ s/bugs,/bugs left join cc on bugs.bug_id = cc.bug_id left join profiles ccname on cc.who = ccname.userid,/;
-}
-
-my $needlongdescs = 0; # Whether we need to patch in the longdescs
- # table.
-
-
-if ($::MFORM{'bug_id'}) {
- my @list = grep(!/^$/, split(/[^0-9]+/, join(',', @{$::MFORM{'bug_id'}})));
- if (@list) {
- my $verb = "IN";
- if ($::FORM{'bugidtype'} && $::FORM{'bugidtype'} eq 'exclude') {
- $verb = "NOT IN";
- }
- $query .= " AND bugs.bug_id $verb (" . join(',', @list) . ") ";
- }
-}
-
-
-
-if (defined $::FORM{'sql'}) {
- $query .= "and (\n$::FORM{'sql'}\n)"
-} else {
- my @legal_fields = ("product", "version", "rep_platform", "op_sys",
- "bug_status", "resolution", "priority", "bug_severity",
- "assigned_to", "reporter", "component",
- "target_milestone", "groupset");
-
- foreach my $field (keys %::FORM) {
- my $or = "";
- if (lsearch(\@legal_fields, $field) != -1 && $::FORM{$field} ne "") {
- $query .= "\tand (\n";
- if ($field eq "assigned_to" || $field eq "reporter") {
- foreach my $p (split(/,/, $::FORM{$field})) {
- my $whoid = DBNameToIdAndCheck($p);
- $query .= "\t\t${or}bugs.$field = $whoid\n";
- $or = "or ";
- }
- } else {
- my $ref = $::MFORM{$field};
- foreach my $v (@$ref) {
- if ($v eq "(empty)") {
- $query .= "\t\t${or}bugs.$field is null\n";
- } else {
- if ($v eq "---") {
- $query .= "\t\t${or}bugs.$field = ''\n";
- } else {
- $query .= "\t\t${or}bugs.$field = " . SqlQuote($v) .
- "\n";
- }
- }
- $or = "or ";
- }
- }
- $query .= "\t)\n";
- }
- }
-}
-
-if ($::FORM{'keywords'}) {
- GetVersionTable();
- my @list;
- foreach my $v (split(/[\s,]+/, $::FORM{'keywords'})) {
- if ($v eq '') {
- next;
- }
- my $id = $::keywordsbyname{$v};
- if ($id) {
- push(@list, "keywords.keywordid = $id");
- } else {
- print "Unknown keyword named <code>$v</code>.\n";
- print "<P>The legal keyword names are <A HREF=describekeywords.cgi>";
- print "listed here</A>.\n";
- print "<P>Please click the <B>Back</B> button and try again.\n";
- PutFooter();
- exit;
- }
- }
- if (@list) {
- $query =~ s/where/, keywords where/;
- my $type = $::FORM{'keywords_type'};
- my $notopt = "";
- if ($type eq "nowords") {
- # Ought to take advantage of keyword table somehow! ###
- my $extra = GetByWordList("bugs.keywords", $::FORM{'keywords'},
- "or");
- $extra =~ s/AND/AND NOT/i;
- $query .= $extra;
- } else {
- $query .= "and keywords.bug_id = bugs.bug_id and $notopt (" .
- join(" or ", @list) . ")\n";
- if ($type eq "allwords") {
- # This needs to be tuned to take better advantage of the
- # keyword table!
- $query .= GetByWordList("bugs.keywords", $::FORM{'keywords'},
- "and");
- }
- }
- }
-}
-
-
-foreach my $id ("1", "2") {
- if (!defined ($::FORM{"email$id"})) {
- next;
- }
- my $email = trim($::FORM{"email$id"});
- if ($email eq "") {
- next;
- }
- my $qemail = SqlQuote($email);
- my $type = $::FORM{"emailtype$id"};
- my $emailid;
- if ($type eq "exact") {
- $emailid = DBNameToIdAndCheck($email);
- }
-
- my $foundone = 0;
- my $lead= "and (\n";
- foreach my $field ("assigned_to", "reporter", "cc", "qa_contact",
- "longdesc") {
- my $doit = $::FORM{"email$field$id"};
- if (!$doit) {
- next;
- }
- $foundone = 1;
- my $table;
- if ($field eq "assigned_to") {
- $table = "assign";
- } elsif ($field eq "reporter") {
- $table = "report";
- } elsif ($field eq "qa_contact") {
- $table = "qacont";
- } elsif ($field eq "longdesc") {
- $table = "longdescname";
- $needlongdescs = 1;
- } else {
- $table = "ccname";
- }
- if ($type eq "exact") {
- if ($field eq "cc") {
- $query .= "\t$lead cc.who = $emailid\n";
- } elsif ($field eq "longdesc") {
- $query .= "\t$lead longdescs.who = $emailid\n";
- } else {
- $query .= "\t$lead $field = $emailid\n";
- }
- } elsif ($type eq "regexp") {
- $query .= "\t$lead $table.login_name regexp $qemail\n";
- } elsif ($type eq "notregexp") {
- $query .= "\t$lead $table.login_name not regexp $qemail\n";
- } else {
- $query .= "\t$lead instr($table.login_name, $qemail)\n";
- }
- $lead = " or ";
- }
- if (!$foundone) {
- print "\n\n<P>You must specify one or more fields in which to search for <tt>$email</tt>.\n";
- print "<P>Please click the <B>Back</B> button and try again.\n";
- PutFooter();
- exit;
- }
- if ($lead eq " or ") {
- $query .= ")\n";
- }
-}
-
-
+my $query = GenerateSQL(\@fields, undef, undef, $::buffer);
-if (defined $::FORM{'changedin'}) {
- my $c = trim($::FORM{'changedin'});
- if ($c ne "") {
- if ($c !~ /^[0-9]*$/) {
- print "\n\n<P>The 'changed in last ___ days' field must be a simple ";
- print "number. You entered \"$c\", which doesn't cut it.";
- print "<P>Please click the <B>Back</B> button and try again.\n";
- PutFooter();
- exit;
- }
- $query .= "and to_days(now()) - to_days(bugs.delta_ts) <= $c ";
- }
-}
-
-if (defined $minvotes) {
- $query .= "and votes >= $minvotes ";
-}
-
-
-my $ref = $::MFORM{'chfield'};
-
-
-sub SqlifyDate {
- my ($str) = (@_);
- if (!defined $str) {
- $str = "";
- }
- my $date = str2time($str);
- if (!defined $date) {
- print "\n\n<P>The string '<tt>$str</tt>' is not a legal date.\n";
- print "<P>Please click the <B>Back</B> button and try again.\n";
- PutFooter();
- exit;
- }
- return time2str("'%Y/%m/%d %H:%M:%S'", $date);
-}
-
-
-if (defined $ref) {
- my $which = lsearch($ref, "[Bug creation]");
- if ($which >= 0) {
- splice(@$ref, $which, 1);
- $query .= "and bugs.creation_ts >= " .
- SqlifyDate($::FORM{'chfieldfrom'}) . "\n";
- my $to = $::FORM{'chfieldto'};
- if (defined $to) {
- $to = trim($to);
- if ($to ne "" && $to !~ /^now$/i) {
- $query .= "and bugs.creation_ts <= " .
- SqlifyDate($to) . "\n";
- }
- }
- }
-}
-
-
-
-if (defined $ref && 0 < @$ref) {
- # Do surgery on the query to tell it to patch in the bugs_activity
- # table.
- $query =~ s/where/, bugs_activity where/;
-
- my @list;
- foreach my $f (@$ref) {
- push(@list, "\nbugs_activity.fieldid = " . GetFieldID($f));
- }
- $query .= "and bugs_activity.bug_id = bugs.bug_id and (" .
- join(' or ', @list) . ") ";
- $query .= "and bugs_activity.bug_when >= " .
- SqlifyDate($::FORM{'chfieldfrom'}) . "\n";
- my $to = $::FORM{'chfieldto'};
- if (defined $to) {
- $to = trim($to);
- if ($to ne "" && $to !~ /^now$/i) {
- $query .= "and bugs_activity.bug_when <= " . SqlifyDate($to) . "\n";
- }
- }
- my $value = $::FORM{'chfieldvalue'};
- if (defined $value) {
- $value = trim($value);
- if ($value ne "") {
- $query .= "and bugs_activity.newvalue = " .
- SqlQuote($value) . "\n";
- }
- }
-}
-
-sub GetByWordList {
- my ($field, $strs, $verb) = (@_);
- my @list;
-
- foreach my $w (split(/[\s,]+/, $strs)) {
- my $word = $w;
- if ($word ne "") {
- $word =~ tr/A-Z/a-z/;
- $word = SqlQuote(quotemeta($word));
- $word =~ s/^'//;
- $word =~ s/'$//;
- $word = '(^|[^a-z0-9])' . $word . '($|[^a-z0-9])';
- push(@list, "lower($field) regexp '$word'");
- }
- }
-
- if (0 == @list) {
- return "";
- }
-
- return "and (" . join(" $verb ", @list) . ")\n";
-}
-
-foreach my $f ("short_desc", "long_desc", "bug_file_loc",
- "status_whiteboard") {
- if (defined $::FORM{$f}) {
- my $s = trim($::FORM{$f});
- if ($s ne "") {
- my $n = $f;
- my $q = SqlQuote($s);
- my $type = $::FORM{$f . "_type"};
- if ($f eq "long_desc") {
- $needlongdescs = 1; # Patch in the longdescs table.
- $query .= "and longdescs.bug_id = bugs.bug_id\n";
- $n = "longdescs.thetext";
- }
- if ($type eq "regexp") {
- $query .= "and $n regexp $q\n";
- } elsif ($type eq "notregexp") {
- $query .= "and $n not regexp $q\n";
- } elsif ($type eq "casesubstring") {
- $query .= "and instr($n, $q)\n";
- } elsif ($type eq "allwords") {
- $query .= GetByWordList($n, $s, "and");
- } elsif ($type eq "anywords") {
- $query .= GetByWordList($n, $s, "or");
- } else {
- $query .= "and instr(lower($n), lower($q))\n";
- }
- }
- }
-}
-
-if ($needlongdescs) {
- $query =~ s/where/, longdescs left join profiles longdescname on longdescs.who = longdescname.userid where/;
- $query .= " AND longdescs.bug_id = bugs.bug_id ";
-}
-
-
-
-$query .= "group by bugs.bug_id\n";
if ($::COOKIE{'LASTORDER'}) {
@@ -644,9 +847,12 @@ if ($::COOKIE{'LASTORDER'}) {
if (defined $::FORM{'order'} && $::FORM{'order'} ne "") {
- $query .= "order by ";
+ $query .= " ORDER BY ";
$::FORM{'order'} =~ s/votesum/bugs.votes/; # Silly backwards compatability
# hack.
+ $::FORM{'order'} =~ s/assign\.login_name/map_assigned_to.login_name/g;
+ # Another backwards compatability hack.
+
ORDER: for ($::FORM{'order'}) {
/\./ && do {
# This (hopefully) already has fieldnames in it, so we're done.
@@ -661,18 +867,18 @@ if (defined $::FORM{'order'} && $::FORM{'order'} ne "") {
last ORDER;
};
/Assign/ && do {
- $::FORM{'order'} = "assign.login_name, bugs.bug_status, priority, bugs.bug_id";
+ $::FORM{'order'} = "map_assigned_to.login_name, bugs.bug_status, priority, bugs.bug_id";
last ORDER;
};
# DEFAULT
- $::FORM{'order'} = "bugs.bug_status, bugs.priority, assign.login_name, bugs.bug_id";
+ $::FORM{'order'} = "bugs.bug_status, bugs.priority, map_assigned_to.login_name, bugs.bug_id";
}
$query .= $::FORM{'order'};
}
if ($::FORM{'debug'} && $serverpush) {
- print "<PRE>$query</PRE>\n";
+ print "<P><CODE>" . value_quote($query) . "</CODE><P>\n";
}
@@ -866,7 +1072,7 @@ print "
<B>" . time2str("%a %b %e %T %Z %Y", time()) . "</B>";
if (defined $::FORM{'debug'}) {
- print "<PRE>$query</PRE>\n";
+ print "<P><CODE>" . value_quote($query) . "</CODE><P>\n";
}
if ($toolong) {