summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--program/lib/Roundcube/rcube_db.php26
-rw-r--r--program/lib/Roundcube/rcube_imap_cache.php82
3 files changed, 88 insertions, 21 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 45d9dab53..7713afe68 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
+- Fix "duplicate entry" errors on inserts to imap cache tables (#1489146)
- Fix so bounces addresses in Sender headers are skipped on Reply-All (#1489011)
- Fix bug where serialized strings were truncated in PDO::quote() (#1489142)
- Improved handling of Reply-To/Bcc addresses of identity in compose form (#1489016)
diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php
index 2d1e32e24..69793b91a 100644
--- a/program/lib/Roundcube/rcube_db.php
+++ b/program/lib/Roundcube/rcube_db.php
@@ -415,13 +415,16 @@ class rcube_db
if ($result === false) {
$error = $this->dbh->errorInfo();
- $this->db_error = true;
- $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
- rcube::raise_error(array('code' => 500, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_error_msg . " (SQL Query: $query)"
- ), true, false);
+ if (empty($this->options['ignore_key_errors']) || $error[0] != '23000') {
+ $this->db_error = true;
+ $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
+
+ rcube::raise_error(array('code' => 500, 'type' => 'db',
+ 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => $this->db_error_msg . " (SQL Query: $query)"
+ ), true, false);
+ }
}
$this->last_result = $result;
@@ -882,6 +885,17 @@ class rcube_db
}
/**
+ * Set class option value
+ *
+ * @param string $name Option name
+ * @param mixed $value Option value
+ */
+ public function set_option($name, $value)
+ {
+ $this->options[$name] = $value;
+ }
+
+ /**
* MDB2 DSN string parser
*
* @param string $sequence Secuence name
diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php
index 71545f1a8..403137f2d 100644
--- a/program/lib/Roundcube/rcube_imap_cache.php
+++ b/program/lib/Roundcube/rcube_imap_cache.php
@@ -437,12 +437,28 @@ class rcube_imap_cache
}
}
+ $this->db->set_option('ignore_key_errors', true);
+
// insert new record
- $this->db->query(
+ $res = $this->db->query(
"INSERT INTO ".$this->db->table_name('cache_messages')
." (user_id, mailbox, uid, flags, changed, data)"
." VALUES (?, ?, ?, ?, ".$this->db->now().", ?)",
$this->userid, $mailbox, (int) $message->uid, $flags, $msg);
+
+ // race-condition, insert failed so try update (#1489146)
+ // thanks to ignore_key_errors "duplicate row" errors will be ignored
+ if ($force && !$res && !$this->db->is_error($res)) {
+ $this->db->query(
+ "UPDATE ".$this->db->table_name('cache_messages')
+ ." SET flags = ?, data = ?, changed = ".$this->db->now()
+ ." WHERE user_id = ?"
+ ." AND mailbox = ?"
+ ." AND uid = ?",
+ $flags, $msg, $this->userid, $mailbox, (int) $message->uid);
+ }
+
+ $this->db->set_option('ignore_key_errors', false);
}
@@ -714,20 +730,38 @@ class rcube_imap_cache
$data = implode('@', $data);
if ($exists) {
- $sql_result = $this->db->query(
+ $res = $this->db->query(
"UPDATE ".$this->db->table_name('cache_index')
." SET data = ?, valid = 1, changed = ".$this->db->now()
." WHERE user_id = ?"
." AND mailbox = ?",
$data, $this->userid, $mailbox);
+
+ if ($this->db->affected_rows($res)) {
+ return;
+ }
}
- else {
- $sql_result = $this->db->query(
- "INSERT INTO ".$this->db->table_name('cache_index')
- ." (user_id, mailbox, data, valid, changed)"
- ." VALUES (?, ?, ?, 1, ".$this->db->now().")",
- $this->userid, $mailbox, $data);
+
+ $this->db->set_option('ignore_key_errors', true);
+
+ $res = $this->db->query(
+ "INSERT INTO ".$this->db->table_name('cache_index')
+ ." (user_id, mailbox, data, valid, changed)"
+ ." VALUES (?, ?, ?, 1, ".$this->db->now().")",
+ $this->userid, $mailbox, $data);
+
+ // race-condition, insert failed so try update (#1489146)
+ // thanks to ignore_key_errors "duplicate row" errors will be ignored
+ if (!$exists && !$res && !$this->db->is_error($res)) {
+ $res = $this->db->query(
+ "UPDATE ".$this->db->table_name('cache_index')
+ ." SET data = ?, valid = 1, changed = ".$this->db->now()
+ ." WHERE user_id = ?"
+ ." AND mailbox = ?",
+ $data, $this->userid, $mailbox);
}
+
+ $this->db->set_option('ignore_key_errors', false);
}
@@ -745,20 +779,38 @@ class rcube_imap_cache
$data = implode('@', $data);
if ($exists) {
- $sql_result = $this->db->query(
+ $res = $this->db->query(
"UPDATE ".$this->db->table_name('cache_thread')
." SET data = ?, changed = ".$this->db->now()
." WHERE user_id = ?"
." AND mailbox = ?",
$data, $this->userid, $mailbox);
+
+ if ($this->db->affected_rows($res)) {
+ return;
+ }
}
- else {
- $sql_result = $this->db->query(
- "INSERT INTO ".$this->db->table_name('cache_thread')
- ." (user_id, mailbox, data, changed)"
- ." VALUES (?, ?, ?, ".$this->db->now().")",
- $this->userid, $mailbox, $data);
+
+ $this->db->set_option('ignore_key_errors', true);
+
+ $res = $this->db->query(
+ "INSERT INTO ".$this->db->table_name('cache_thread')
+ ." (user_id, mailbox, data, changed)"
+ ." VALUES (?, ?, ?, ".$this->db->now().")",
+ $this->userid, $mailbox, $data);
+
+ // race-condition, insert failed so try update (#1489146)
+ // thanks to ignore_key_errors "duplicate row" errors will be ignored
+ if (!$exists && !$res && !$this->db->is_error($res)) {
+ $this->db->query(
+ "UPDATE ".$this->db->table_name('cache_thread')
+ ." SET data = ?, changed = ".$this->db->now()
+ ." WHERE user_id = ?"
+ ." AND mailbox = ?",
+ $data, $this->userid, $mailbox);
}
+
+ $this->db->set_option('ignore_key_errors', false);
}