summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbuglist.cgi198
1 files changed, 111 insertions, 87 deletions
diff --git a/buglist.cgi b/buglist.cgi
index 9c2632359..a0340cc29 100755
--- a/buglist.cgi
+++ b/buglist.cgi
@@ -57,6 +57,7 @@ use vars qw($db_name
@versions);
my $cgi = Bugzilla->cgi;
+my $dbh = Bugzilla->dbh;
if (length($::buffer) == 0) {
print $cgi->header(-refresh=> '10; URL=query.cgi');
@@ -195,10 +196,13 @@ sub iCalendarDateTime {
sub LookupNamedQuery {
my ($name) = @_;
Bugzilla->login(LOGIN_REQUIRED);
- my $userid = Bugzilla->user->id;
- my $qname = SqlQuote($name);
- SendSQL("SELECT query FROM namedqueries WHERE userid = $userid AND name = $qname");
- my $result = FetchOneColumn();
+ my $dbh = Bugzilla->dbh;
+ # $name is safe -- we only use it below in a SELECT placeholder and then
+ # in error messages (which are always HTML-filtered).
+ trick_taint($name);
+ my $result = $dbh->selectrow_array("SELECT query FROM namedqueries"
+ . " WHERE userid = ? AND name = ?"
+ , undef, (Bugzilla->user->id, $name));
defined($result) || ThrowUserError("missing_query", {'queryname' => $name});
$result
@@ -207,60 +211,114 @@ sub LookupNamedQuery {
return $result;
}
+# Inserts a Named Query (a "Saved Search") into the database, or
+# updates a Named Query that already exists..
+# Takes four arguments:
+# userid - The userid who the Named Query will belong to.
+# query_name - A string that names the new Named Query, or the name
+# of an old Named Query to update. If this is blank, we
+# will throw a UserError. Leading and trailing whitespace
+# will be stripped from this value before it is inserted
+# into the DB.
+# query - The query part of the buglist.cgi URL, unencoded. Must not be
+# empty, or we will throw a UserError.
+# link_in_footer (optional) - 1 if the Named Query should be
+# displayed in the user's footer, 0 otherwise.
+#
+# All parameters are validated before passing them into the database.
+#
+# Returns: A boolean true value if the query existed in the database
+# before, and we updated it. A boolean false value otherwise.
+sub InsertNamedQuery ($$$;$) {
+ my ($userid, $query_name, $query, $link_in_footer) = @_;
+ $link_in_footer ||= 0;
+ $query_name = trim($query_name);
+ Bugzilla->login(LOGIN_REQUIRED);
+ my $dbh = Bugzilla->dbh;
+ my $query_existed_before;
+
+ # Validate the query name.
+ $query_name || ThrowUserError("query_name_missing");
+ $query_name !~ /[<>&]/ || ThrowUserError("illegal_query_name");
+ trick_taint($query_name);
+
+ detaint_natural($userid);
+ detaint_natural($link_in_footer);
+
+ $query || ThrowUserError("buglist_parameters_required",
+ {'queryname' => $query});
+ # $query is safe, because we always urlencode or html_quote
+ # it when we display it to the user.
+ trick_taint($query);
+
+ $dbh->do("LOCK TABLES namedqueries WRITE");
+
+ my $result = $dbh->selectrow_array("SELECT userid FROM namedqueries"
+ . " WHERE userid = ? AND name = ?"
+ , undef, ($userid, $query_name));
+ if ($result) {
+ $query_existed_before = 1;
+ $dbh->do("UPDATE namedqueries"
+ . " SET query = ?, linkinfooter = ?"
+ . " WHERE userid = ? AND name = ?"
+ , undef, ($query, $link_in_footer, $userid, $query_name));
+ } else {
+ $query_existed_before = 0;
+ $dbh->do("INSERT INTO namedqueries"
+ . " (userid, name, query, linkinfooter)"
+ . " VALUES (?, ?, ?, ?)"
+ , undef, ($userid, $query_name, $query, $link_in_footer));
+ }
+
+ $dbh->do("UNLOCK TABLES");
+ return $query_existed_before;
+}
+
sub LookupSeries {
my ($series_id) = @_;
detaint_natural($series_id) || ThrowCodeError("invalid_series_id");
my $dbh = Bugzilla->dbh;
my $result = $dbh->selectrow_array("SELECT query FROM series " .
- "WHERE series_id = $series_id");
+ "WHERE series_id = ?"
+ , undef, ($series_id));
$result
|| ThrowCodeError("invalid_series_id", {'series_id' => $series_id});
return $result;
}
sub GetQuip {
-
- my $quip;
-
+ my $dbh = Bugzilla->dbh;
# COUNT is quick because it is cached for MySQL. We may want to revisit
# this when we support other databases.
-
- SendSQL("SELECT COUNT(quip) FROM quips WHERE approved = 1");
- my $count = FetchOneColumn();
+ my $count = $dbh->selectrow_array("SELECT COUNT(quip)"
+ . " FROM quips WHERE approved = 1");
my $random = int(rand($count));
- SendSQL("SELECT quip FROM quips WHERE approved = 1 LIMIT $random,1");
-
- if (MoreSQLData()) {
- ($quip) = FetchSQLData();
- }
-
+ my $quip =
+ $dbh->selectrow_array("SELECT quip FROM quips"
+ . " WHERE approved = 1 LIMIT $random,1");
return $quip;
}
sub GetGroupsByUserId {
my ($userid) = @_;
+ my $dbh = Bugzilla->dbh;
return if !$userid;
- SendSQL("
- SELECT DISTINCT groups.id, name, description, isactive
+ # Create an array where each item is a hash. The hash contains
+ # as keys the name of the columns, which point to the value of
+ # the columns for that row.
+ my $groups = $dbh->selectall_arrayref(
+ "SELECT DISTINCT groups.id, name, description, isactive
FROM groups, user_group_map
- WHERE user_id = $userid AND isbless = 0
+ WHERE user_id = ? AND isbless = 0
AND user_group_map.group_id = groups.id
AND isbuggroup = 1
- ORDER BY description ");
-
- my @groups;
+ ORDER BY description "
+ , {}, ($userid));
- while (MoreSQLData()) {
- my $group = {};
- ($group->{'id'}, $group->{'name'},
- $group->{'description'}, $group->{'isactive'}) = FetchSQLData();
- push(@groups, $group);
- }
-
- return \@groups;
+ return $groups;
}
@@ -319,9 +377,14 @@ if ($::FORM{'cmdtype'} eq "dorem") {
}
elsif ($::FORM{'remaction'} eq "forget") {
Bugzilla->login(LOGIN_REQUIRED);
- my $userid = Bugzilla->user->id;
- my $qname = SqlQuote($::FORM{'namedcmd'});
- SendSQL("DELETE FROM namedqueries WHERE userid = $userid AND name = $qname");
+ # Copy the name into a variable, so that we can trick_taint it for
+ # the DB. We know it's safe, because we're using placeholders in
+ # the SQL, and the SQL is only a DELETE.
+ my $qname = $::FORM{'namedcmd'};
+ trick_taint($qname);
+ $dbh->do("DELETE FROM namedqueries"
+ . " WHERE userid = ? AND name = ?"
+ , undef, ($userid, $qname));
# Now reset the cached queries
Bugzilla->user->flush_queries_cache();
@@ -339,70 +402,29 @@ if ($::FORM{'cmdtype'} eq "dorem") {
elsif (($::FORM{'cmdtype'} eq "doit") && $::FORM{'remtype'}) {
if ($::FORM{'remtype'} eq "asdefault") {
Bugzilla->login(LOGIN_REQUIRED);
- my $userid = Bugzilla->user->id;
- my $qname = SqlQuote(DEFAULT_QUERY_NAME);
- my $qbuffer = SqlQuote($::buffer);
-
- SendSQL("LOCK TABLES namedqueries WRITE");
-
- SendSQL("SELECT userid FROM namedqueries WHERE userid = $userid " .
- "AND name = $qname");
- my $result = FetchOneColumn();
- if ($result) {
- SendSQL("UPDATE namedqueries SET query = $qbuffer " .
- "WHERE userid = $userid AND name = $qname");
- } else {
- SendSQL("INSERT INTO namedqueries (userid, name, query, linkinfooter) VALUES " .
- "($userid, $qname, $qbuffer, 0)");
- }
-
- SendSQL("UNLOCK TABLES");
-
+ InsertNamedQuery(Bugzilla->user->id, DEFAULT_QUERY_NAME, $::buffer);
$vars->{'message'} = "buglist_new_default_query";
}
elsif ($::FORM{'remtype'} eq "asnamed") {
Bugzilla->login(LOGIN_REQUIRED);
my $userid = Bugzilla->user->id;
+ my $query_name = $::FORM{'newqueryname'};
- my $name = trim($::FORM{'newqueryname'});
- $name || ThrowUserError("query_name_missing");
- $name !~ /[<>&]/ || ThrowUserError("illegal_query_name");
- my $qname = SqlQuote($name);
-
- $::FORM{'newquery'} || ThrowUserError("buglist_parameters_required",
- {'queryname' => $name});
- my $qbuffer = SqlQuote($::FORM{'newquery'});
-
my $tofooter = 1;
-
- $vars->{'message'} = "buglist_new_named_query";
-
- # We want to display the correct message. Check if it existed before
- # we insert, because ->queries may fetch from the db anyway
- if (grep { $_->{name} eq $name } @{Bugzilla->user->queries()}) {
+ my $existed_before = InsertNamedQuery($userid, $query_name,
+ $::FORM{'newquery'}, $tofooter);
+ if ($existed_before) {
$vars->{'message'} = "buglist_updated_named_query";
}
-
- SendSQL("LOCK TABLES namedqueries WRITE");
-
- SendSQL("SELECT query FROM namedqueries WHERE userid = $userid AND name = $qname");
- if (FetchOneColumn()) {
- SendSQL("UPDATE namedqueries
- SET query = $qbuffer , linkinfooter = $tofooter
- WHERE userid = $userid AND name = $qname");
- }
else {
- SendSQL("INSERT INTO namedqueries (userid, name, query, linkinfooter)
- VALUES ($userid, $qname, $qbuffer, $tofooter)");
+ $vars->{'message'} = "buglist_new_named_query";
}
- SendSQL("UNLOCK TABLES");
-
# Make sure to invalidate any cached query data, so that the footer is
# correctly displayed
Bugzilla->user->flush_queries_cache();
- $vars->{'queryname'} = $name;
+ $vars->{'queryname'} = $query_name;
print $cgi->header();
$template->process("global/message.html.tmpl", $vars)
@@ -766,7 +788,8 @@ $::SIG{TERM} = 'DEFAULT';
$::SIG{PIPE} = 'DEFAULT';
# Execute the query.
-SendSQL($query);
+my $buglist_sth = $dbh->prepare($query);
+$buglist_sth->execute();
################################################################################
@@ -783,7 +806,7 @@ my @bugidlist;
my @bugs; # the list of records
-while (my @row = FetchSQLData()) {
+while (my @row = $buglist_sth->fetchrow_array()) {
my $bug = {}; # a record
# Slurp the row of data into the record.
@@ -833,7 +856,8 @@ while (my @row = FetchSQLData()) {
# or because of human choice
my %min_membercontrol;
if (@bugidlist) {
- SendSQL("SELECT DISTINCT bugs.bug_id, MIN(group_control_map.membercontrol) " .
+ my $sth = $dbh->prepare("SELECT DISTINCT bugs.bug_id, " .
+ "MIN(group_control_map.membercontrol) " .
"FROM bugs, bug_group_map " .
"LEFT JOIN group_control_map " .
"ON group_control_map.product_id=bugs.product_id " .
@@ -841,8 +865,8 @@ if (@bugidlist) {
"WHERE bugs.bug_id = bug_group_map.bug_id " .
"AND bugs.bug_id IN (" . join(',',@bugidlist) . ") " .
"GROUP BY bugs.bug_id");
- while (MoreSQLData()) {
- my ($bug_id, $min_membercontrol) = FetchSQLData();
+ $sth->execute();
+ while (my ($bug_id, $min_membercontrol) = $sth->fetchrow_array()) {
$min_membercontrol{$bug_id} = $min_membercontrol;
}
foreach my $bug (@bugs) {