Browse Source

Added modifiers support for UPDATE statements

Jose Lorenzo Rodriguez 10 years ago
parent
commit
747eb2dcc7

+ 33 - 5
src/Database/QueryCompiler.php

@@ -31,7 +31,6 @@ class QueryCompiler
      */
     protected $_templates = [
         'delete' => 'DELETE',
-        'update' => 'UPDATE %s',
         'where' => ' WHERE %s',
         'group' => ' GROUP BY %s ',
         'having' => ' HAVING %s ',
@@ -56,7 +55,7 @@ class QueryCompiler
      *
      * @var array
      */
-    protected $_updateParts = ['update', 'modifier', 'set', 'where', 'epilog'];
+    protected $_updateParts = ['update', 'set', 'where', 'epilog'];
 
     /**
      * The list of query clauses to traverse for generating a DELETE statement
@@ -309,12 +308,40 @@ class QueryCompiler
         return implode('', $this->_stringifyExpressions($parts, $generator));
     }
 
+    /**
+     * Builds the SQL fragment for UPDATE.
+     *
+     * @param array $parts The update parts.
+     * @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 SQL fragment.
+     */
+    protected function _buildUpdatePart($parts, $query, $generator)
+    {
+        $table = $this->_stringifyExpressions($parts, $generator);
+        $modifiers = $this->_buildModifierPart($query->clause('modifier'), $query, $generator);
+
+        if ($modifiers !== null) {
+            $modifiers .= ' ';
+        }
+
+        return sprintf('UPDATE %s%s', $modifiers, implode(',', $table));
+    }
+
+    /**
+     * Builds the SQL modifier fragment
+     *
+     * @param array $parts The query modifier parts
+     * @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 SQL fragment.
+     */
     protected function _buildModifierPart($parts, $query, $generator)
     {
         if ($parts === []) {
             return null;
         }
-        return implode(' ', $this->_stringifyExpressions($parts, $generator));
+        return implode(' ', $this->_stringifyExpressions($parts, $generator, false));
     }
 
     /**
@@ -323,15 +350,16 @@ class QueryCompiler
      *
      * @param array $expressions list of strings and ExpressionInterface objects
      * @param \Cake\Database\ValueBinder $generator the placeholder generator to be used in expressions
+     * @param bool $wrap Whether to wrap each expression object with parenthesis
      * @return array
      */
-    protected function _stringifyExpressions($expressions, $generator)
+    protected function _stringifyExpressions($expressions, $generator, $wrap = true)
     {
         $result = [];
         foreach ($expressions as $k => $expression) {
             if ($expression instanceof ExpressionInterface) {
                 $value = $expression->sql($generator);
-                $expression = '(' . $value . ')';
+                $expression = $wrap ? '(' . $value . ')' : $value;
             }
             $result[$k] = $expression;
         }

+ 4 - 1
src/Database/SqlserverCompiler.php

@@ -35,7 +35,6 @@ class SqlserverCompiler extends QueryCompiler
      */
     protected $_templates = [
         'delete' => 'DELETE',
-        'update' => 'UPDATE %s',
         'where' => ' WHERE %s',
         'group' => ' GROUP BY %s ',
         'having' => ' HAVING %s ',
@@ -70,6 +69,10 @@ class SqlserverCompiler extends QueryCompiler
         $columns = $this->_stringifyExpressions($parts[1], $generator);
         $modifiers = $this->_buildModifierPart($query->clause('modifier'), $query, $generator);
 
+        if ($modifiers !== null) {
+            $modifiers .= ' ';
+        }
+
         return sprintf('INSERT %sINTO %s (%s) OUTPUT INSERTED.*',
             $modifiers,
             $table,

+ 43 - 0
tests/TestCase/Database/QueryTest.php

@@ -3670,6 +3670,49 @@ class QueryTest extends TestCase
     }
 
     /**
+     * Test use of modifiers in a UPDATE query
+     *
+     * Testing the generated SQL since the modifiers are usually different per driver
+     *
+     * @return void
+     */
+    public function testUpdateModifiers()
+    {
+        $query = new Query($this->connection);
+        $result = $query
+            ->update('authors')
+            ->set('name', 'mark')
+            ->modifier('TOP 10 PERCENT');
+        $this->assertQuotedQuery(
+            'UPDATE TOP 10 PERCENT <authors> SET <name> = :c0',
+            $result->sql(),
+            !$this->autoQuote
+        );
+
+        $query = new Query($this->connection);
+        $result = $query
+            ->update('authors')
+            ->set('name', 'mark')
+            ->modifier(['TOP 10 PERCENT', 'FOO']);
+        $this->assertQuotedQuery(
+            'UPDATE TOP 10 PERCENT FOO <authors> SET <name> = :c0',
+            $result->sql(),
+            !$this->autoQuote
+        );
+
+        $query = new Query($this->connection);
+        $result = $query
+            ->update('authors')
+            ->set('name', 'mark')
+            ->modifier([$query->newExpr('TOP 10 PERCENT')]);
+        $this->assertQuotedQuery(
+            'UPDATE TOP 10 PERCENT <authors> SET <name> = :c0',
+            $result->sql(),
+            !$this->autoQuote
+        );
+    }
+
+    /**
      * Assertion for comparing a table's contents with what is in it.
      *
      * @param string $table