From d1ec92f25598d4a92227ac753a8f6f3be2598425 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 11 Aug 2014 12:48:57 -0400 Subject: [PATCH] Alternate fix to delete queries with aliases. I goofed on the last set of changes and mainlined a MySQLism. Since we don't support joins in delete queries, and database vendors either don't support aliases in delete queries (sqlite) or support them in different ways (mysql, postgres, sqlserver) it is simpler to manipulate queries before they are rendered removing table and condition aliases. --- src/Database/QueryCompiler.php | 25 +------------------- src/Database/SqlDialectTrait.php | 40 +++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/Database/QueryCompiler.php b/src/Database/QueryCompiler.php index e97ddf14842..0da685955bb 100644 --- a/src/Database/QueryCompiler.php +++ b/src/Database/QueryCompiler.php @@ -32,6 +32,7 @@ class QueryCompiler { * @var array */ protected $_templates = [ + 'delete' => 'DELETE', 'update' => 'UPDATE %s', 'where' => ' WHERE %s', 'group' => ' GROUP BY %s ', @@ -158,30 +159,6 @@ protected function _buildSelectPart($parts, $query, $generator) { return sprintf($select, $modifiers, $distinct, implode(', ', $normalized)); } -/** - * Helper function used to build the string representation of a DELETE clause. - * - * If the table is aliased, a `DELETE x` fragment will be returned - * - * @param array $parts list of tables to be transformed to string - * @param \Cake\Database\Query $query The query that is being compiled - * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions - * @return string - */ - protected function _buildDeletePart($parts, $query, $generator) { - $delete = 'DELETE'; - $aliases = []; - foreach ($query->clause('from') as $k => $v) { - if (is_string($k)) { - $aliases[] = $k; - } - } - if (!empty($aliases)) { - $delete = trim($delete . ' ' . implode(',', $aliases)); - } - return $delete; - } - /** * Helper function used to build the string representation of a FROM clause, * it constructs the tables list taking care of aliasing and diff --git a/src/Database/SqlDialectTrait.php b/src/Database/SqlDialectTrait.php index c3d40aa71fc..1175d849d85 100644 --- a/src/Database/SqlDialectTrait.php +++ b/src/Database/SqlDialectTrait.php @@ -14,6 +14,8 @@ */ namespace Cake\Database; +use Cake\Database\Expression\Comparison; + /** * Sql dialect trait */ @@ -129,14 +131,50 @@ protected function _transformDistinct($query) { } return $query; } - /** + * * Apply translation steps to delete queries. * + * Chops out aliases on delete query conditions as most database dialects do not + * support aliases in delete queries. This also removes aliases + * in table names as they frequently don't work either. + * + * We are intentionally not supporting deletes with joins as they have even poorer support. + * * @param Query $query The query to translate * @return Query The modified query */ protected function _deleteQueryTranslator($query) { + $hadAlias = false; + $tables = []; + foreach ($query->clause('from') as $alias => $table) { + if (is_string($alias)) { + $hadAlias = true; + } + $tables[] = $table; + } + if ($hadAlias) { + $query->from($tables, true); + } + + if (!$hadAlias) { + return $query; + } + $conditions = $query->clause('where'); + if ($conditions) { + $conditions->iterateParts(function($condition, $key) { + if (!($condition instanceof Comparison)) { + return $condition; + } + $field = $condition->getField(); + if (strpos($field, '.') !== false) { + list(, $field) = explode('.', $field); + $condition->field($field); + } + return $condition; + }); + } + return $query; }