diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-06-26 01:40:05 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-06-26 01:40:05 +0000 |
commit | 5ca8621ba40016315be9a081814b31586920ff30 (patch) | |
tree | c595fb557b61fa920b308aa6e0bc8b8e4dbd3bfb /includes/database/mysql | |
parent | 60883871aab067f13bd3411bfd2874b50cfe7978 (diff) | |
download | brdo-5ca8621ba40016315be9a081814b31586920ff30.tar.gz brdo-5ca8621ba40016315be9a081814b31586920ff30.tar.bz2 |
- Patch #715108 by Damien Tournoud, Berdir, Josh Waihi, Crell, chx, justinrandell: Make merge queries more consistent and robust.
Diffstat (limited to 'includes/database/mysql')
-rw-r--r-- | includes/database/mysql/query.inc | 120 |
1 files changed, 9 insertions, 111 deletions
diff --git a/includes/database/mysql/query.inc b/includes/database/mysql/query.inc index 63c0fe8e7..584a4a473 100644 --- a/includes/database/mysql/query.inc +++ b/includes/database/mysql/query.inc @@ -87,121 +87,19 @@ class InsertQuery_mysql extends InsertQuery { } } -class MergeQuery_mysql extends MergeQuery { - - public function execute() { - - // A merge query without any key field is invalid. - if (count($this->keyFields) == 0) { - throw new InvalidMergeQueryException("You need to specify key fields before executing a merge query"); - } - - // Set defaults. - if ($this->updateFields) { - $update_fields = $this->updateFields; - } - else { - // When update fields are derived from insert fields, we don't need - // placeholders since we can tell MySQL to reuse insert supplied - // values using the VALUES(col_name) function. - $update_fields = array(); - } - - $insert_fields = $this->insertFields + $this->keyFields; - - $max_placeholder = 0; - $values = array(); - // We assume that the order here is the same as in __toString(). If that's - // not the case, then we have serious problems. - foreach ($insert_fields as $value) { - $values[':db_insert_placeholder_' . $max_placeholder++] = $value; - } - - // Expressions take priority over literal fields, so we process those first - // and remove any literal fields that conflict. - foreach ($this->expressionFields as $field => $data) { - if (!empty($data['arguments'])) { - $values += $data['arguments']; - } - unset($update_fields[$field]); - } - - // Because we filter $fields the same way here and in __toString(), the - // placeholders will all match up properly. - $max_placeholder = 0; - foreach ($update_fields as $field => $value) { - $values[':db_update_placeholder_' . ($max_placeholder++)] = $value; - } - - - // MySQL's INSERT ... ON DUPLICATE KEY UPDATE queries return 1 - // (MergeQuery::STATUS_INSERT) for an INSERT operation or 2 - // (MergeQuery::STATUS_UPDATE) for an UPDATE operation. - // - // @link http ://dev.mysql.com/doc/refman/5.0/en/mysql-affected-rows.html - $this->queryOptions['return'] = Database::RETURN_AFFECTED; - return $this->connection->query((string) $this, $values, $this->queryOptions); - } - - +class TruncateQuery_mysql extends TruncateQuery { public function __toString() { - // Create a comments string to prepend to the query. - $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; - - // Set defaults. - if ($this->updateFields) { - $update_fields = $this->updateFields; + // TRUNCATE is actually a DDL statement on MySQL, and DDL statements are + // not transactional, and result in an implicit COMMIT. When we are in a + // transaction, fallback to the slower, but transactional, DELETE. + if ($this->connection->inTransaction()) { + // Create a comments string to prepend to the query. + $comments = (!empty($this->comments)) ? '/* ' . implode('; ', $this->comments) . ' */ ' : ''; + return $comments . 'DELETE FROM {' . $this->connection->escapeTable($this->table) . '}'; } else { - $update_fields = $this->insertFields; - // If there are no exclude fields, this is a no-op. - foreach ($this->excludeFields as $exclude_field) { - unset($update_fields[$exclude_field]); - } - } - - // If the merge query has no fields to update, add the first key as an - // update field so the query will not fail if a duplicate key is found. - if (!$update_fields && !$this->expressionFields) { - $update_fields = array_slice($this->keyFields, 0, 1, TRUE); - } - - $insert_fields = $this->insertFields + $this->keyFields; - - $query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', array_keys($insert_fields)) . ') VALUES '; - - $max_placeholder = 0; - $values = array(); - // We don't need the $field, but this is a convenient way to count. - foreach ($insert_fields as $field) { - $values[] = ':db_insert_placeholder_' . $max_placeholder++; + return parent::__toString(); } - - $query .= '(' . implode(', ', $values) . ') ON DUPLICATE KEY UPDATE '; - - // Expressions take priority over literal fields, so we process those first - // and remove any literal fields that conflict. - $max_placeholder = 0; - $update = array(); - foreach ($this->expressionFields as $field => $data) { - $update[] = $field . '=' . $data['expression']; - unset($update_fields[$field]); - } - - // Build update fields clauses based on caller supplied list, or derived - // from insert supplied values using the VALUES(col_name) function. - foreach ($update_fields as $field => $value) { - if ($this->updateFields) { - $update[] = ($field . '=:db_update_placeholder_' . $max_placeholder++); - } - else { - $update[] = ($field . '=VALUES(' . $field . ')'); - } - } - - $query .= implode(', ', $update); - - return $query; } } |