From notifications_event_tracker() in notifications.cron.inc:

385  case 'update':
386        foreach ($events as $eid => $count) {
387          db_query('UPDATE {notifications_event} SET counter = counter - %d WHERE eid = %d', $count, $eid);
388        }

I encountered this by chance and have yet to be able to reproduce the conditions that caused it (I'll update this if I do). At some point on my site, this update statement tried to set the counter to a value below zero, which is a problem since counter is unsigned. As of MySQL 5.5.5, this will generate the error "BIGINT UNSIGNED value is out of range in ..." (see bottom of http://dev.mysql.com/doc/refman/5.5/en/out-of-range-and-overflow.html)

Regardless of how this error might have happened, there should be protection in place to prevent a value less than zero from being assigned to counter. Maybe something along the lines of

db_query('UPDATE {notifications_event} SET counter = GREATEST(counter - %d, 0) WHERE eid = %d', $count, $eid);
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nnewton’s picture

I hit this recently with a 5.5 update, definitely a problem. I think this: "GREATEST(counter - %d, 0)" needs a CAST though, because MySQL 5.5 will make the result of a subtraction unsigned if any element of the subtraction is unsigned (so the actual expression eval will likely throw an error). You can disabled this in 5.5 by setting the SQL mode to NO_UNSIGNED_SUBTRACTION, but the correct way is with a cast I believe.

-N

christianchristensen’s picture

Please find an attached patch that follows this idea of GREATEST(CAST AS INTEGER

greggles’s picture

Status: Active » Needs review