Commit a48e3706 authored by dmose%mozilla.org's avatar dmose%mozilla.org

allow users to watch the bugs of other users

parent 5bfbabbd
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Mosedale <dmose@mozilla.org>
# Terry Weissman <terry@mozilla.org>
# This object models a set of relations between one item and a group
# of other items. An example is the set of relations between one bug
# and the users CCed on that bug. Currently, the relation objects are
# expected to be bugzilla userids. However, this could and perhaps
# should be generalized to work with non userid objects, such as
# keywords associated with a bug. That shouldn't be hard to do; it
# might involve turning this into a virtual base class, and having
# UserSet and KeywordSet types that inherit from it.
use diagnostics;
use strict;
require "globals.pl";
package RelationSet;
use CGI::Carp qw(fatalsToBrowser);
# create a new empty RelationSet
#
sub new {
my $type = shift();
# create a ref to an empty hash and bless it
#
my $self = {};
bless $self, $type;
# construct from a comma-delimited string
#
if ($#_ == 0) {
$self->mergeFromString($_[0]);
}
# unless this was a constructor for an empty list, somebody screwed up.
#
elsif ( $#_ != -1 ) {
confess("invalid number of arguments");
}
# bless as a RelationSet
#
return $self;
}
# Assumes that the set of relations "FROM $table WHERE $constantSql and
# $column = $value" is currently represented by $self, and this set should
# be updated to look like $other.
#
# Returns an array of two strings, one INSERT and one DELETE, which will
# make this change. Either or both strings may be the empty string,
# meaning that no INSERT or DELETE or both (respectively) need to be done.
#
# THE CALLER IS RESPONSIBLE FOR ANY DESIRED LOCKING AND/OR CONSISTENCY
# CHECKS (not to mention doing the SendSQL() calls).
#
sub generateSqlDeltas {
($#_ == 5) || confess("invalid number of arguments");
my ( $self, # instance ptr to set representing the existing state
$endState, # instance ptr to set representing the desired state
$table, # table where these relations are kept
$invariantName, # column held const for a RelationSet (often "bug_id")
$invariantValue, # what to hold the above column constant at
$columnName # the column which varies (often a userid)
) = @_;
# construct the insert list by finding relations which exist in the
# end state but not the current state.
#
my @endStateRelations = keys(%$endState);
my @insertList = ();
foreach ( @endStateRelations ) {
push ( @insertList, $_ ) if ( ! exists $$self{"$_"} );
}
# we've built the list. If it's non-null, add required sql chrome.
#
my $sqlInsert="";
if ( $#insertList > -1 ) {
$sqlInsert = "INSERT INTO $table ($invariantName, $columnName) VALUES " .
join (",",
map ( "($invariantValue, $_)" , @insertList )
);
}
# construct the delete list by seeing which relations exist in the
# current state but not the end state
#
my @selfRelations = keys(%$self);
my @deleteList = ();
foreach ( @selfRelations ) {
push (@deleteList, $_) if ( ! exists $$endState{"$_"} );
}
# we've built the list. if it's non-empty, add required sql chrome.
#
my $sqlDelete = "";
if ( $#deleteList > -1 ) {
$sqlDelete = "DELETE FROM $table WHERE $invariantName = $invariantValue " .
"AND $columnName IN ( " . join (",", @deleteList) . " )";
}
return ($sqlInsert, $sqlDelete);
}
# compare the current object with another.
#
sub isEqual {
($#_ == 1) || confess("invalid number of arguments");
my $self = shift();
my $other = shift();
# get arrays of the keys for faster processing
#
my @selfRelations = keys(%$self);
my @otherRelations = keys(%$other);
# make sure the arrays are the same size
#
return 0 if ( $#selfRelations != $#otherRelations );
# bail out if any of the elements are different
#
foreach my $relation ( @selfRelations ) {
return 0 if ( !exists $$other{$relation})
}
# we made it!
#
return 1;
}
# merge the results of a SQL command into this set
#
sub mergeFromDB {
( $#_ == 1 ) || confess("invalid number of arguments");
my $self = shift();
&::SendSQL(shift());
while (my @row = &::FetchSQLData()) {
$$self{$row[0]} = 1;
}
return;
}
# merge a set in string form into this set
#
sub mergeFromString {
($#_ == 1) || confess("invalid number of arguments");
my $self = shift();
# do the merge
#
foreach my $person (split(/[ ,]/, shift())) {
if ($person ne "") {
$$self{&::DBNameToIdAndCheck($person)} = 1;
}
}
}
# return the number of elements in this set
#
sub size {
my $self = shift();
my @k = keys(%$self);
return $#k++;
}
# return this set in array form
#
sub toArray {
my $self= shift();
return keys(%$self);
}
# return this set in string form (comma-separated and sorted)
#
sub toString {
($#_ == 0) || confess("invalid number of arguments");
my $self = shift();
my @result = ();
foreach my $i ( keys %$self ) {
push @result, &::DBID_to_name($i);
}
return join(',', sort(@result));
}
......@@ -26,7 +26,7 @@ other necessary ingredient is a web server set up to run cgi scripts.
The software packages necessary for the proper running of bugzilla are:
1. MySQL database server and the mysql client
1. MySQL database server and the mysql client (3.22.5 or greater)
2. Perl (5.004 or greater)
3. DBI Perl module
4. Data::Dumper Perl module
......@@ -39,7 +39,7 @@ other necessary ingredient is a web server set up to run cgi scripts.
Bugzilla has quite a few prerequisites, but none of them are TCL.
Previous versions required TCL, but it no longer needed (or used).
1.1. Getting and setting up MySQL database
1.1. Getting and setting up MySQL database (3.22.5 or greater)
Visit MySQL homepage at http://www.mysql.org and grab the latest stable
release of the server. Both binaries and source are available and which
......
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 2000 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dan Mosedale <dmose@mozilla.org>
# Terry Weissman <terry@mozilla.org>
# This object models a set of relations between one item and a group
# of other items. An example is the set of relations between one bug
# and the users CCed on that bug. Currently, the relation objects are
# expected to be bugzilla userids. However, this could and perhaps
# should be generalized to work with non userid objects, such as
# keywords associated with a bug. That shouldn't be hard to do; it
# might involve turning this into a virtual base class, and having
# UserSet and KeywordSet types that inherit from it.
use diagnostics;
use strict;
require "globals.pl";
package RelationSet;
use CGI::Carp qw(fatalsToBrowser);
# create a new empty RelationSet
#
sub new {
my $type = shift();
# create a ref to an empty hash and bless it
#
my $self = {};
bless $self, $type;
# construct from a comma-delimited string
#
if ($#_ == 0) {
$self->mergeFromString($_[0]);
}
# unless this was a constructor for an empty list, somebody screwed up.
#
elsif ( $#_ != -1 ) {
confess("invalid number of arguments");
}
# bless as a RelationSet
#
return $self;
}
# Assumes that the set of relations "FROM $table WHERE $constantSql and
# $column = $value" is currently represented by $self, and this set should
# be updated to look like $other.
#
# Returns an array of two strings, one INSERT and one DELETE, which will
# make this change. Either or both strings may be the empty string,
# meaning that no INSERT or DELETE or both (respectively) need to be done.
#
# THE CALLER IS RESPONSIBLE FOR ANY DESIRED LOCKING AND/OR CONSISTENCY
# CHECKS (not to mention doing the SendSQL() calls).
#
sub generateSqlDeltas {
($#_ == 5) || confess("invalid number of arguments");
my ( $self, # instance ptr to set representing the existing state
$endState, # instance ptr to set representing the desired state
$table, # table where these relations are kept
$invariantName, # column held const for a RelationSet (often "bug_id")
$invariantValue, # what to hold the above column constant at
$columnName # the column which varies (often a userid)
) = @_;
# construct the insert list by finding relations which exist in the
# end state but not the current state.
#
my @endStateRelations = keys(%$endState);
my @insertList = ();
foreach ( @endStateRelations ) {
push ( @insertList, $_ ) if ( ! exists $$self{"$_"} );
}
# we've built the list. If it's non-null, add required sql chrome.
#
my $sqlInsert="";
if ( $#insertList > -1 ) {
$sqlInsert = "INSERT INTO $table ($invariantName, $columnName) VALUES " .
join (",",
map ( "($invariantValue, $_)" , @insertList )
);
}
# construct the delete list by seeing which relations exist in the
# current state but not the end state
#
my @selfRelations = keys(%$self);
my @deleteList = ();
foreach ( @selfRelations ) {
push (@deleteList, $_) if ( ! exists $$endState{"$_"} );
}
# we've built the list. if it's non-empty, add required sql chrome.
#
my $sqlDelete = "";
if ( $#deleteList > -1 ) {
$sqlDelete = "DELETE FROM $table WHERE $invariantName = $invariantValue " .
"AND $columnName IN ( " . join (",", @deleteList) . " )";
}
return ($sqlInsert, $sqlDelete);
}
# compare the current object with another.
#
sub isEqual {
($#_ == 1) || confess("invalid number of arguments");
my $self = shift();
my $other = shift();
# get arrays of the keys for faster processing
#
my @selfRelations = keys(%$self);
my @otherRelations = keys(%$other);
# make sure the arrays are the same size
#
return 0 if ( $#selfRelations != $#otherRelations );
# bail out if any of the elements are different
#
foreach my $relation ( @selfRelations ) {
return 0 if ( !exists $$other{$relation})
}
# we made it!
#
return 1;
}
# merge the results of a SQL command into this set
#
sub mergeFromDB {
( $#_ == 1 ) || confess("invalid number of arguments");
my $self = shift();
&::SendSQL(shift());
while (my @row = &::FetchSQLData()) {
$$self{$row[0]} = 1;
}
return;
}
# merge a set in string form into this set
#
sub mergeFromString {
($#_ == 1) || confess("invalid number of arguments");
my $self = shift();
# do the merge
#
foreach my $person (split(/[ ,]/, shift())) {
if ($person ne "") {
$$self{&::DBNameToIdAndCheck($person)} = 1;
}
}
}
# return the number of elements in this set
#
sub size {
my $self = shift();
my @k = keys(%$self);
return $#k++;
}
# return this set in array form
#
sub toArray {
my $self= shift();
return keys(%$self);
}
# return this set in string form (comma-separated and sorted)
#
sub toString {
($#_ == 0) || confess("invalid number of arguments");
my $self = shift();
my @result = ();
foreach my $i ( keys %$self ) {
push @result, &::DBID_to_name($i);
}
return join(',', sort(@result));
}
......@@ -22,6 +22,8 @@
use diagnostics;
use strict;
use RelationSet;
# Shut up misguided -w warnings about "used only once". For some reason,
# "use vars" chokes on me when I try it here.
......@@ -147,8 +149,10 @@ my $sev_popup = make_options(\@::legal_severity, $bug{'bug_severity'});
my $component_popup = make_options($::components{$bug{'product'}},
$bug{'component'});
my $ccSet = new RelationSet;
$ccSet->mergeFromDB("select who from cc where bug_id=$id");
my $cc_element = '<INPUT NAME=cc SIZE=30 VALUE="' .
ShowCcList($id) . '">';
$ccSet->toString() . '">';
my $URL = $bug{'bug_file_loc'};
......@@ -208,7 +212,9 @@ if (Param("usetargetmilestone")) {
if ($url eq "") {
$url = "notargetmilestone.html";
}
if ($bug{'target_milestone'} eq "") {
$bug{'target_milestone'} = " ";
}
print "
<TD ALIGN=RIGHT><A href=\"$url\"><B>Target Milestone:</B></A></TD>
<TD><SELECT NAME=target_milestone>" .
......
......@@ -20,6 +20,7 @@
#
# Contributor(s): Holger Schurig <holgerschurig@nikocity.de>
# Terry Weissman <terry@mozilla.org>
# Dan Mosedale <dmose@mozilla.org>
#
#
# Direct any questions on this source code to
......@@ -591,8 +592,15 @@ $table{cc} =
'bug_id mediumint not null,
who mediumint not null,
index(bug_id),
index(who)';
index(who),
unique(bug_id,who)';
$table{watch} =
'watcher mediumint not null,
watched mediumint not null,
index(watched),
unique(watcher,watched)';
$table{longdescs} =
......@@ -742,8 +750,8 @@ $table{keywords} =
'bug_id mediumint not null,
keywordid smallint not null,
index(bug_id),
index(keywordid)';
index(keywordid),
unique(bug_id,keywordid)';
$table{keyworddefs} =
'id smallint not null primary key,
......@@ -994,6 +1002,49 @@ sub GetIndexDef ($$)
}
}
sub CountIndexes ($)
{
my ($table) = @_;
my $sth = $dbh->prepare("SHOW INDEX FROM $table");
$sth->execute;
if ( $sth->rows == -1 ) {
die ("Unexpected response while counting indexes in $table:" .
" \$sth->rows == -1");
}
return ($sth->rows);
}
sub DropIndexes ($)
{
my ($table) = @_;
my %SEEN;
# get the list of indexes
#
my $sth = $dbh->prepare("SHOW INDEX FROM $table");
$sth->execute;
# drop each index
#
while ( my $ref = $sth->fetchrow_arrayref) {
# note that some indexes are described by multiple rows in the
# index table, so we may have already dropped the index described
# in the current row.
#
next if exists $SEEN{$$ref[2]};
my $dropSth = $dbh->prepare("ALTER TABLE $table DROP INDEX $$ref[2]");
$dropSth->execute;
$dropSth->finish;
$SEEN{$$ref[2]} = 1;
}
}
#
# Check if the enums in the bugs table return the same values that are defined
# in the various locally changeable variables. If this is true, then alter the
......@@ -1506,7 +1557,6 @@ AddField('products', 'maxvotesperbug', 'smallint not null default 10000');
AddField('products', 'votestoconfirm', 'smallint not null');
AddField('profiles', 'blessgroupset', 'bigint not null');
# 2000-03-21 Adding a table for target milestones to
# database - matthew@zeroknowledge.com
......@@ -1577,6 +1627,29 @@ if (!GetFieldDef('products', 'defaultmilestone')) {
}
}
# 2000-03-24 Added unique indexes into the cc and keyword tables. This
# prevents certain database inconsistencies, and, moreover, is required for
# new generalized list code to work.
if ( CountIndexes('cc') != 3 ) {
# XXX should eliminate duplicate entries before altering
#
print "Recreating indexes on cc table.\n";
DropIndexes('cc');
$dbh->do("ALTER TABLE cc ADD UNIQUE (bug_id,who)");
$dbh->do("ALTER TABLE cc ADD INDEX (who)");
}
if ( CountIndexes('keywords') != 3 ) {
# XXX should eliminate duplicate entries before altering
#
print "Recreating indexes on keywords table.\n";
DropIndexes('keywords');
$dbh->do("ALTER TABLE keywords ADD INDEX (keywordid)");
$dbh->do("ALTER TABLE keywords ADD UNIQUE (bug_id,keywordid)");
}
#
# If you had to change the --TABLE-- definition in any way, then add your
......@@ -1594,4 +1667,6 @@ if ($regenerateshadow) {
print "Now regenerating the shadow database for all bugs.\n";
system("./processmail regenerate");
}
unlink "data/versioncache";
print "Reminder: Bugzilla now requires version 3.22.5 or later of MySQL.\n";
......@@ -550,6 +550,10 @@ DefParam("commentonclose",
DefParam("commentonduplicate",
"If this option is on, the user needs to enter a short comment if the bug is marked as duplicate",
"b", 0 );
DefParam("supportwatchers",
"Support one user watching (ie getting copies of all related email" .
" about) another's bugs. Useful for people going on vacation, and" .
" QA folks watching particular developers' bugs",
"b", 0 );
1;
......@@ -18,6 +18,7 @@
# Rights Reserved.
#
# Contributor(s): Terry Weissman <terry@mozilla.org>
# Dan Mosedale <dmose@mozilla.org>
# Contains some global variables and routines used throughout bugzilla.
......@@ -65,6 +66,7 @@ use Mysql;
use Date::Format; # For time2str().
use Date::Parse; # For str2time().
# use Carp; # for confess
use RelationSet;
# Contains the version string for the current running Bugzilla.
$::param{'version'} = '2.9';
......@@ -118,9 +120,6 @@ sub SqlLog {
}
}
sub SendSQL {
my ($str, $dontshadow) = (@_);
my $iswrite = ($str =~ /^(INSERT|REPLACE|UPDATE|DELETE)/i);
......@@ -756,23 +755,13 @@ sub GetLongDescriptionAsHTML {
}
sub ShowCcList {
my ($num) = (@_);
my @ccids;
my @row;
SendSQL("select who from cc where bug_id = $num");
while (@row = FetchSQLData()) {
push(@ccids, $row[0]);
}
my @result = ();
foreach my $i (@ccids) {
push @result, DBID_to_name($i);
}
return join(',', @result);
my ($num) = (@_);
my $ccSet = new RelationSet();
$ccSet->mergeFromDB("select who from cc where bug_id=$num");
return $ccSet->toString();
}
# Fills in a hashtable with info about the columns for the given table in the
# database. The hashtable has the following entries:
# -list- the list of column names
......@@ -903,7 +892,7 @@ sub RemoveVotes {
}
sub Param {
sub Param ($) {
my ($value) = (@_);
if (defined $::param{$value}) {
return $::param{$value};
......
......@@ -28,6 +28,7 @@ my $UserInEditGroupSet = -1;
my $UserInCanConfirmGroupSet = -1;
require "CGI.pl";
use RelationSet;
# Shut up misguided -w warnings about "used only once":
......@@ -373,24 +374,21 @@ if (defined $::FORM{'qa_contact'}) {
ConnectToDatabase();
my %ccids;
my $origcclist = "";
my $formCcSet = new RelationSet;
my $origCcSet = new RelationSet;
my $origCcString;
# We make sure to check out the CC list before we actually start touching any
# bugs.
# bugs. mergeFromString() ultimately searches the database using a quoted
# form of the data it gets from $::FORM{'cc'}, so anything bogus from a
# security standpoint should trigger an abort there.
#
if (defined $::FORM{'cc'} && defined $::FORM{'id'}) {
$origcclist = ShowCcList($::FORM{'id'});
if ($origcclist ne $::FORM{'cc'}) {
foreach my $person (split(/[ ,]/, $::FORM{'cc'})) {
if ($person ne "") {
my $cid = DBNameToIdAndCheck($person);
$ccids{$cid} = 1;
}
}
}
$origCcSet->mergeFromDB("select who from cc where bug_id = $::FORM{'id'}");
$origCcString = $origCcSet->toString(); # cache a copy of the string vers
$formCcSet->mergeFromString($::FORM{'cc'});
}
if ( Param('strictvaluechecks') ) {
CheckFormFieldDefined(\%::FORM, 'knob');
}
......@@ -759,22 +757,25 @@ The changes made were:
AppendComment($id, $::FORM{'who'}, $::FORM{'comment'});
}
if (defined $::FORM{'cc'} && $origcclist ne $::FORM{'cc'}) {
SendSQL("delete from cc where bug_id = $id");
foreach my $ccid (keys %ccids) {
SendSQL("insert into cc (bug_id, who) values ($id, $ccid)");
}
my $newcclist = ShowCcList($id);
if ($newcclist ne $origcclist) {
my $col = GetFieldID('cc');
my $origq = SqlQuote($origcclist);
my $newq = SqlQuote($newcclist);
SendSQL("INSERT INTO bugs_activity " .
"(bug_id,who,bug_when,fieldid,oldvalue,newvalue) VALUES " .
"($id,$whoid,'$timestamp',$col,$origq,$newq)");
}
}
if (defined $::FORM{'cc'} && defined $::FORM{'id'}
&& ! $origCcSet->isEqual($formCcSet) ) {
# update the database to look like the form
#
my @CCDELTAS = $origCcSet->generateSqlDeltas($formCcSet, "cc",
"bug_id", $::FORM{'id'},
"who");
$CCDELTAS[0] eq "" || SendSQL($CCDELTAS[0]);
$CCDELTAS[1] eq "" || SendSQL($CCDELTAS[1]);
my $col = GetFieldID('cc');
my $origq = SqlQuote($origCcString);
my $newq = SqlQuote($::FORM{'cc'});
SendSQL("INSERT INTO bugs_activity " .
"(bug_id,who,bug_when,fieldid,oldvalue,newvalue) VALUES " .
"($id,$whoid,'$timestamp',$col,$origq,$newq)");
}
if (defined $::FORM{'dependson'}) {
my $me = "blocked";
......@@ -850,9 +851,9 @@ The changes made were:
if ($col eq 'assigned_to' || $col eq 'qa_contact') {
$old = DBID_to_name($old) if $old != 0;
$new = DBID_to_name($new) if $new != 0;
$origcclist .= ",$old"; # make sure to send mail to people
# if they are going to no longer get
# updates about this bug.
$origCcString .= ",$old"; # make sure to send mail to people
# if they are going to no longer get
# updates about this bug.
}
if ($col eq 'product') {
RemoveVotes($id, 0,
......@@ -869,7 +870,7 @@ The changes made were:
print "<TABLE BORDER=1><TD><H2>Changes to bug $id submitted</H2>\n";
SendSQL("unlock tables");
system("./processmail", "-forcecc", $origcclist, $id, $::FORM{'who'});
system("./processmail", "-forcecc", $origCcString, $id, $::FORM{'who'});
print "<TD><A HREF=\"show_bug.cgi?id=$id\">Back To BUG# $id</A></TABLE>\n";
foreach my $k (keys(%dependencychanged)) {
......
......@@ -14,12 +14,15 @@
# The Original Code is the Bugzilla Bug Tracking System.
#
# Contributor(s): Terry Weissman <terry@mozilla.org>
# Dan Mosedale <dmose@mozilla.org>
use diagnostics;
use strict;
require "CGI.pl";
use RelationSet;
# Shut up misguided -w warnings about "used only once". "use vars" just
# doesn't work for me.
sub sillyness {
......@@ -134,6 +137,29 @@ risk any bugs), check here.
EmitEntry("Check here to sign up (and risk any bugs)",
qq{<INPUT TYPE="checkbox" NAME="newemailtech" $checkedpart>New email tech});
}
if (Param("supportwatchers")) {
my $watcheduserSet = new RelationSet;
$watcheduserSet->mergeFromDB("SELECT watched FROM watch WHERE" .
" watcher=$userid");
my $watchedusers = $watcheduserSet->toString();
print qq{
<TR><TD COLSPAN="2"><HR></TD></TR>
<TR><TD COLSPAN="2"><FONT COLOR="red">New!</FONT>
If you want to help cover for someone when they're on vacation, or if
you need to do the QA related to all of their bugs, you can tell bugzilla
to send mail related to their bugs to you also. List the email addresses
of any users you wish to watch here, separated by commas.
<FONT COLOR="red">Note that you MUST have the above "New email tech"
button selected in order to use this feature.</FONT>
</TD></TR>
};
EmitEntry("Users to watch",
qq{<INPUT SIZE=35 NAME="watchedusers" VALUE="$watchedusers">});
}
}
sub SaveDiffs {
......@@ -144,6 +170,47 @@ sub SaveDiffs {
SendSQL("UPDATE profiles " .
"SET emailnotification = " . SqlQuote($::FORM{'emailnotification'})
. ", newemailtech = $newemailtech WHERE userid = $userid");
# deal with any watchers
#
if (Param("supportwatchers") ) {
if (exists $::FORM{'watchedusers'}) {
Error ('You must have "New email tech" set to watch someone')
if ( $::FORM{'watchedusers'} ne "" && $newemailtech == 0);
# Just in case. Note that this much locking is actually overkill:
# we don't really care if anyone reads the watch table. So
# some small amount of contention could be gotten rid of by
# using user-defined locks rather than table locking.
#
SendSQL("LOCK TABLES watch WRITE, profiles READ");
# what the db looks like now
#
my $origWatchedUsers = new RelationSet;
$origWatchedUsers->mergeFromDB("SELECT watched FROM watch WHERE" .
" watcher=$userid");
# update the database to look like the form
#
my $newWatchedUsers = new RelationSet($::FORM{'watchedusers'});
my @CCDELTAS = $origWatchedUsers->generateSqlDeltas(
$newWatchedUsers,
"watch",
"watcher",
$userid,
"watched");
$CCDELTAS[0] eq "" || SendSQL($CCDELTAS[0]);
$CCDELTAS[1] eq "" || SendSQL($CCDELTAS[1]);
# all done
#
SendSQL("UNLOCK TABLES");
}
}
}
......
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