in lib/Mail/SpamAssassin/BayesStore/SQL.pm [1842:2024]
sub _put_token {
my ($self, $token, $spam_count, $ham_count, $atime) = @_;
return 0 unless (defined($self->{_dbh}));
$spam_count ||= 0;
$ham_count ||= 0;
if ($spam_count == 0 && $ham_count == 0) {
return 1;
}
my ($existing_spam_count,
$existing_ham_count,
$existing_atime) = $self->tok_get($token);
if (!$existing_atime) {
# You can't create a new entry for a token with a negative count, so just return
# if we are unable to find an entry.
return 1 if ($spam_count < 0 || $ham_count < 0);
my $sql = "INSERT INTO bayes_token
(id, token, spam_count, ham_count, atime)
VALUES (?,?,?,?,?)";
my $sth = $self->{_dbh}->prepare_cached($sql);
unless (defined($sth)) {
dbg("bayes: _put_token: SQL error: ".$self->{_dbh}->errstr());
return 0;
}
my $rc = $sth->execute($self->{_userid},
$token,
$spam_count,
$ham_count,
$atime);
unless ($rc) {
dbg("bayes: _put_token: SQL error: ".$self->{_dbh}->errstr());
return 0;
}
$sth->finish();
$sql = "UPDATE bayes_vars SET token_count = token_count + 1
WHERE id = ?";
my $rows = $self->{_dbh}->do($sql, undef, $self->{_userid});
unless (defined($rows)) {
dbg("bayes: _put_token: SQL error: ".$self->{_dbh}->errstr());
return 0;
}
$sql = "UPDATE bayes_vars SET newest_token_age = ?
WHERE id = ? AND newest_token_age < ?";
$rows = $self->{_dbh}->do($sql, undef, $atime, $self->{_userid}, $atime);
unless (defined($rows)) {
dbg("bayes: _put_token: SQL error: ".$self->{_dbh}->errstr());
return 0;
}
if ($rows eq '0E0') {
# no need to update oldest_token_age if we updated newest_token_age
$sql = "UPDATE bayes_vars SET oldest_token_age = ?
WHERE id = ? AND oldest_token_age > ?";
$rows = $self->{_dbh}->do($sql, undef, $atime, $self->{_userid}, $atime);
unless (defined($rows)) {
dbg("bayes: _put_token: SQL error: ".$self->{_dbh}->errstr());
return 0;
}
}
}
else {
if ($spam_count < 0 || $ham_count < 0) {
# we only need to cleanup when we subtract counts for a token and the
# counts may have both reached 0
# XXX - future optimization, since we have the existing spam/ham counts
# we can make an educated guess on if the count would reach 0, for
# instance, if we are decreasing spam_count but spam_count is currently
# > 1000, then there is no possible way this update or any others that
# might currently be happening could reduce that value to 0, so there
# would be no need to set the needs_cleanup flag
$self->{needs_cleanup} = 1;
}
my $update_atime_p = 1;
my $updated_atime_p = 0;
# if the existing atime is already >= the one we are going to set, then
# don't bother
$update_atime_p = 0 if ($existing_atime >= $atime);
# These SQL statements include as part of the WHERE clause something like
# "AND spam_count + ? >= 0" or "AND ham_count + ? >= 0". This is to keep
# the count from going negative.
if ($spam_count) {
my $sql;
my @args;
if ($update_atime_p) {
$sql = "UPDATE bayes_token
SET spam_count = spam_count + ?,
atime = ?
WHERE id = ?
AND token = ?
AND spam_count + ? >= 0";
@args = ($spam_count, $atime, $self->{_userid}, $token, $spam_count);
$updated_atime_p = 1; # note the fact that we did do it
}
else {
$sql = "UPDATE bayes_token
SET spam_count = spam_count + ?
WHERE id = ?
AND token = ?
AND spam_count + ? >= 0";
@args = ($spam_count, $self->{_userid}, $token, $spam_count);
}
my $rows = $self->{_dbh}->do($sql, undef, @args);
unless (defined($rows)) {
dbg("bayes: _put_token: SQL error: ".$self->{_dbh}->errstr());
return 0;
}
}
if ($ham_count) {
my $sql;
my @args;
if ($update_atime_p && !$updated_atime_p) {
$sql = "UPDATE bayes_token
SET ham_count = ham_count + ?,
atime = ?
WHERE id = ?
AND token = ?
AND ham_count + ? >= 0";
@args = ($ham_count, $atime, $self->{_userid}, $token, $ham_count);
$updated_atime_p = 1; # note the fact that we did do it
}
else {
$sql = "UPDATE bayes_token
SET ham_count = ham_count + ?
WHERE id = ?
AND token = ?
AND ham_count + ? >= 0";
@args = ($ham_count, $self->{_userid}, $token, $ham_count);
}
my $rows = $self->{_dbh}->do($sql, undef, @args);
unless (defined($rows)) {
dbg("bayes: _put_token: SQL error: ".$self->{_dbh}->errstr());
return 0;
}
}
if ($updated_atime_p) {
# we updated the atime, so we need to check and update bayes_vars
# we only need to worry about newest_token_age since we would have
# only updated the atime if it was > the previous value
my $sql = "UPDATE bayes_vars SET newest_token_age = ?
WHERE id = ? AND newest_token_age < ?";
my $rows = $self->{_dbh}->do($sql, undef, $atime, $self->{_userid}, $atime);
unless (defined($rows)) {
dbg("bayes: _put_token: SQL error: ".$self->{_dbh}->errstr());
return 0;
}
}
}
return 1;
}