Aleksander Machniak
2013-06-05 be4b5c2fe57fbf667e24d3042239e75f48a6bd78
Fix "duplicate entry" errors on inserts to imap cache tables (#1489146)
3 files modified
113 ■■■■ changed files
CHANGELOG 1 ●●●● patch | view | raw | blame | history
program/lib/Roundcube/rcube_db.php 26 ●●●● patch | view | raw | blame | history
program/lib/Roundcube/rcube_imap_cache.php 86 ●●●● patch | view | raw | blame | history
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)
program/lib/Roundcube/rcube_db.php
@@ -415,13 +415,16 @@
        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 @@
    }
    /**
     * 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
program/lib/Roundcube/rcube_imap_cache.php
@@ -437,12 +437,28 @@
            }
        }
        $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 @@
        $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;
            }
        }
        $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);
        }
        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', false);
    }
@@ -745,20 +779,38 @@
        $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;
            }
        }
        $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);
        }
        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', false);
    }