Skip to content

Loading…

rework of pull request #354 on issue #124 #525

Merged
merged 6 commits into from

3 participants

@cebe
Yii Software LLC member

cleanup of @DaSourcerer's pull request #354 on issue #124

the new CMysqlCommandBuilder overides the complete method but the only difference to the original implementation is

line 61-63 and 100-103 each:

-    $sql="UPDATE {$table->rawName} SET ".implode(', ',$fields);
+    $sql="UPDATE {$table->rawName}";
     $sql=$this->applyJoin($sql,$criteria->join);
+    $sql.=" SET ".implode(', ',$fields);

and lines 68 + 106:

-    $command=$this->_connection->createCommand($sql);
+    $command=$this->getDbConnection()->createCommand($sql);

Tested this with my application and a unit test is also attached so I think it is ready for merge now.

DaSourcerer and others added some commits
@DaSourcerer DaSourcerer Add CMysqlCommandBuilder to handle joins on update
Fixes issue #124
CDbCommandBuilder produced faulty mysql update queries
when joins are involved. JOIN has to come before SET in mysql.
4ac67ea
@DaSourcerer DaSourcerer added some unit tests mysql
testing mysql update commands with new CMysqlCommandBuilder
issue #124
5100f24
@cebe cebe added docblocks to CMysqlCommandBuilder+CHANGELOG fdabdb2
@cebe cebe added @since annotation f37a3da
@cebe cebe referenced this pull request
Closed

Issue #124 #354

@qiangxue
Yii Software LLC member

That's quite some duplicated code. Could you please check if other DBMS supports similar syntax? If so, we should modify CDbCommandBuilder.php directly. Even if it is not, we should still try to refactor the code to avoid copy large chunk of code.

@cebe
Yii Software LLC member

Okay, will check it.

@DaSourcerer

A little support: The command builder seems to be fine with pgsql. Oracle will need a subquery for the same functionailty. And this seems to be outright impossible all on SQLite.

@DaSourcerer

w/o link: mssql seems to be content with what the unaltered command builder provides.

@DaSourcerer

bump
Any news on this?

@cebe
Yii Software LLC member

nope, sorry have not much time at the moment.

@DaSourcerer

That's okay. But this has been left withoug a notice on Google Code for almost half a year before, so I just want to make sure it's not forgotten.

@cebe cebe was assigned
cebe added some commits
@cebe cebe Merge branch 'master' of https://github.com/yiisoft/yii into issue-124
* 'master' of https://github.com/yiisoft/yii: (651 commits)
  Updated guide Gii Model Generator page screenshot.
  adjusted CHANGELOG
  Requirements checking slightly improved.
  Enhanced CHANGELOG description
  Requirements checker: added support of the Oracle database (pdo_oci extension)
  MSSQL driver types refinements.
  Requirements checker: added support of the MSSQL (pdo_dblib and pdo_sqlsrv extensions).
  Language fixes.
  Preparations for merging fixes of the #556 into 1.1.13 codebase.
  [docs][blog] 'yiic' to 'Gii'
  ajaxUpdate is never false in jquery.yiilistview.js
  Added /docs/guide/fr/caching.overview.twt
  Added /docs/guide/fr/basics.controller.txt
  Added /docs/guide/fr/basics.mvc.txt
  Update framework/web/filters/CHttpCacheFilter.php
  Update docs/guide/fr/toc.txt
  [NL] Dutch messages translation updated
  added history.js license
  prepare for next release.
  prepare for 1.1.12 release.
  ...

Conflicts:
	CHANGELOG
d77234b
@cebe cebe better fix for issues #124
changed position of JOIN in UPDATE by overwriting applyJoin()
266df50
@cebe
Yii Software LLC member

Found a better solution by overwriting applyJoin() and insert JOIN part before SET.

@DaSourcerer

Nice. No idea why this didn't occur to me in the first place.

@cebe cebe merged commit 266df50 into yiisoft:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 19, 2012
  1. @DaSourcerer @cebe

    Add CMysqlCommandBuilder to handle joins on update

    DaSourcerer committed with cebe
    Fixes issue #124
    CDbCommandBuilder produced faulty mysql update queries
    when joins are involved. JOIN has to come before SET in mysql.
  2. @DaSourcerer @cebe

    added some unit tests mysql

    DaSourcerer committed with cebe
    testing mysql update commands with new CMysqlCommandBuilder
    issue #124
  3. @cebe
  4. @cebe

    added @since annotation

    cebe committed
Commits on Aug 28, 2012
  1. @cebe

    Merge branch 'master' of https://github.com/yiisoft/yii into issue-124

    cebe committed
    * 'master' of https://github.com/yiisoft/yii: (651 commits)
      Updated guide Gii Model Generator page screenshot.
      adjusted CHANGELOG
      Requirements checking slightly improved.
      Enhanced CHANGELOG description
      Requirements checker: added support of the Oracle database (pdo_oci extension)
      MSSQL driver types refinements.
      Requirements checker: added support of the MSSQL (pdo_dblib and pdo_sqlsrv extensions).
      Language fixes.
      Preparations for merging fixes of the #556 into 1.1.13 codebase.
      [docs][blog] 'yiic' to 'Gii'
      ajaxUpdate is never false in jquery.yiilistview.js
      Added /docs/guide/fr/caching.overview.twt
      Added /docs/guide/fr/basics.controller.txt
      Added /docs/guide/fr/basics.mvc.txt
      Update framework/web/filters/CHttpCacheFilter.php
      Update docs/guide/fr/toc.txt
      [NL] Dutch messages translation updated
      added history.js license
      prepare for next release.
      prepare for 1.1.12 release.
      ...
    
    Conflicts:
    	CHANGELOG
  2. @cebe

    better fix for issues #124

    cebe committed
    changed position of JOIN in UPDATE by overwriting applyJoin()
View
1 CHANGELOG
@@ -3,6 +3,7 @@
Version 1.1.13 work in progress
-------------------------------
+- Bug #124: Added CMysqlCommandBuilder to handle JOIN directive on update commands correctly (cebe, DaSourcerer)
- Enh #556: CDbColumnSchema::$comment property has been added. It stores comment for the table column, comment retrieving is working for MySQL, PgSQL and Oracle (resurtm)
- Enh: Fixed the check for ajaxUpdate false value in jquery.yiilistview.js as that never happens (mdomba)
- Enh: Requirements checker: added check for Oracle database (pdo_oci extension) and MSSQL (pdo_dblib, pdo_sqlsrv and pdo_mssql extensions) (resurtm)
View
1 framework/YiiBase.php
@@ -707,6 +707,7 @@ public static function registerAutoloader($callback, $append=false)
'CMssqlSchema' => '/db/schema/mssql/CMssqlSchema.php',
'CMssqlTableSchema' => '/db/schema/mssql/CMssqlTableSchema.php',
'CMysqlColumnSchema' => '/db/schema/mysql/CMysqlColumnSchema.php',
+ 'CMysqlCommandBuilder' => '/db/schema/mysql/CMysqlCommandBuilder.php',
'CMysqlSchema' => '/db/schema/mysql/CMysqlSchema.php',
'CMysqlTableSchema' => '/db/schema/mysql/CMysqlTableSchema.php',
'COciColumnSchema' => '/db/schema/oci/COciColumnSchema.php',
View
37 framework/db/schema/mysql/CMysqlCommandBuilder.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * CMysqlCommandBuilder class file.
+ *
+ * @author Carsten Brandt <mail@cebe.cc>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CMysqlCommandBuilder provides basic methods to create query commands for tables.
+ *
+ * @author Carsten Brandt <mail@cebe.cc>
+ * @package system.db.schema.mysql
+ * @since 1.1.13
+ */
+class CMysqlCommandBuilder extends CDbCommandBuilder
+{
+ /**
+ * Alters the SQL to apply JOIN clause.
+ * This method handles the mysql specific syntax where JOIN has to come before SET in UPDATE statement
+ * @param string $sql the SQL statement to be altered
+ * @param string $join the JOIN clause (starting with join type, such as INNER JOIN)
+ * @return string the altered SQL statement
+ */
+ public function applyJoin($sql,$join)
+ {
+ if($join=='')
+ return $sql;
+
+ if(strpos($sql,'UPDATE')===0 && ($pos=strpos($sql,'SET'))!==false)
+ return substr($sql,0,$pos).$join.' '.substr($sql,$pos);
+ else
+ return $sql.' '.$join;
+ }
+}
View
11 framework/db/schema/mysql/CMysqlSchema.php
@@ -257,6 +257,17 @@ protected function findTableNames($schema='')
}
/**
+ * Creates a command builder for the database.
+ * This method overrides parent implementation in order to create a MySQL specific command builder
+ * @return CDbCommandBuilder command builder instance
+ * @since 1.1.13
+ */
+ protected function createCommandBuilder()
+ {
+ return new CMysqlCommandBuilder($this);
+ }
+
+ /**
* Builds a SQL statement for renaming a column.
* @param string $table the table whose column is to be renamed. The name will be properly quoted by the method.
* @param string $name the old name of the column. The name will be properly quoted by the method.
View
28 tests/framework/db/schema/CMysqlTest.php
@@ -179,16 +179,36 @@ public function testCommandBuilder()
'condition'=>'id=:id',
'params'=>array('id'=>5))));
$this->assertEquals('new post 5',$c->queryScalar());
-
+
$c=$builder->createSqlCommand('SELECT title FROM posts WHERE id=:id',array(':id'=>3));
$this->assertEquals('post 3',$c->queryScalar());
- $c=$builder->createUpdateCounterCommand($table,array('author_id'=>-2),new CDbCriteria(array('condition'=>'id=5')));
- $this->assertEquals('UPDATE `posts` SET `author_id`=`author_id`-2 WHERE id=5',$c->text);
+ $c=$builder->createUpdateCounterCommand($table,array('author_id'=>-1),new CDbCriteria(array('condition'=>'id=5')));
+ $this->assertEquals('UPDATE `posts` SET `author_id`=`author_id`-1 WHERE id=5',$c->text);
$c->execute();
$c=$builder->createSqlCommand('SELECT author_id FROM posts WHERE id=5');
+ $this->assertEquals(2,$c->queryScalar());
+
+ // test for updates with joins
+ $c=$builder->createUpdateCommand($table,array('title'=>'new post 1'),new CDbCriteria(array(
+ 'condition'=>'u.`username`=:username',
+ 'join'=>'JOIN `users` u ON `author_id`=u.`id`',
+ 'params'=>array(':username'=>'user1'))));
+ $c->execute();
+ $c=$builder->createFindCommand($table,new CDbCriteria(array(
+ 'select'=>'title',
+ 'condition'=>'id=:id',
+ 'params'=>array('id'=>1))));
+ $this->assertEquals('new post 1',$c->queryScalar());
+
+ $c=$builder->createUpdateCounterCommand($table,array('author_id'=>-1),new CDbCriteria(array(
+ 'condition'=>'u.`username`="user2"',
+ 'join'=>'JOIN `users` u ON `author_id`=u.`id`')));
+ $this->assertEquals('UPDATE `posts` JOIN `users` u ON `author_id`=u.`id` SET `author_id`=`author_id`-1 WHERE u.`username`="user2"',$c->text);
+ $c->execute();
+ $c=$builder->createSqlCommand('SELECT author_id FROM posts WHERE id=2');
$this->assertEquals(1,$c->queryScalar());
-
+
// test bind by position
$c=$builder->createFindCommand($table,new CDbCriteria(array(
'select'=>'title',
Something went wrong with that request. Please try again.