From bc378d1cae6e180034db2d5dc0a34b51ea5dd202 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Wed, 26 Mar 2014 15:02:56 -0400 Subject: [PATCH] properly quote table names for join(). --- framework/db/ActiveQuery.php | 2 +- framework/db/QueryBuilder.php | 57 +++++++++----------- tests/unit/framework/db/ActiveRecordTest.php | 5 ++ 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/framework/db/ActiveQuery.php b/framework/db/ActiveQuery.php index 05904548b2..25b0d6d67c 100644 --- a/framework/db/ActiveQuery.php +++ b/framework/db/ActiveQuery.php @@ -524,7 +524,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface } else { $on = $child->on; } - $this->join($joinType, $childTable, $on); + $this->join($joinType, empty($child->from) ? $childTable : $child->from, $on); if (!empty($child->where)) { $this->andWhere($child->where); diff --git a/framework/db/QueryBuilder.php b/framework/db/QueryBuilder.php index 1c94b34f1e..a974a22173 100644 --- a/framework/db/QueryBuilder.php +++ b/framework/db/QueryBuilder.php @@ -642,23 +642,7 @@ class QueryBuilder extends \yii\base\Object return ''; } - foreach ($tables as $i => $table) { - if ($table instanceof Query) { - list($sql, $params) = $this->build($table, $params); - $tables[$i] = "($sql) " . $this->db->quoteTableName($i); - } elseif (is_string($i)) { - if (strpos($table, '(') === false) { - $table = $this->db->quoteTableName($table); - } - $tables[$i] = "$table " . $this->db->quoteTableName($i); - } elseif (strpos($table, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { // with alias - $tables[$i] = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]); - } else { - $tables[$i] = $this->db->quoteTableName($table); - } - } - } + $tables = $this->quoteTableNames($tables, $params); return 'FROM ' . implode(', ', $tables); } @@ -681,21 +665,8 @@ class QueryBuilder extends \yii\base\Object } // 0:join type, 1:join table, 2:on-condition (optional) list ($joinType, $table) = $join; - if (is_array($table)) { - $query = reset($table); - if (!$query instanceof Query) { - throw new Exception('The sub-query for join must be an instance of yii\db\Query.'); - } - $alias = $this->db->quoteTableName(key($table)); - list ($sql, $params) = $this->build($query, $params); - $table = "($sql) $alias"; - } elseif (strpos($table, '(') === false) { - if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { // with alias - $table = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]); - } else { - $table = $this->db->quoteTableName($table); - } - } + $tables = $this->quoteTableNames((array)$table, $params); + $table = reset($tables); $joins[$i] = "$joinType $table"; if (isset($join[2])) { $condition = $this->buildCondition($join[2], $params); @@ -708,6 +679,28 @@ class QueryBuilder extends \yii\base\Object return implode($this->separator, $joins); } + private function quoteTableNames($tables, &$params) + { + foreach ($tables as $i => $table) { + if ($table instanceof Query) { + list($sql, $params) = $this->build($table, $params); + $tables[$i] = "($sql) " . $this->db->quoteTableName($i); + } elseif (is_string($i)) { + if (strpos($table, '(') === false) { + $table = $this->db->quoteTableName($table); + } + $tables[$i] = "$table " . $this->db->quoteTableName($i); + } elseif (strpos($table, '(') === false) { + if (preg_match('/^(.*?)(?i:\s+as|)\s+([^ ]+)$/', $table, $matches)) { // with alias + $tables[$i] = $this->db->quoteTableName($matches[1]) . ' ' . $this->db->quoteTableName($matches[2]); + } else { + $tables[$i] = $this->db->quoteTableName($table); + } + } + } + return $tables; + } + /** * @param string|array $condition * @param array $params the binding parameters to be populated diff --git a/tests/unit/framework/db/ActiveRecordTest.php b/tests/unit/framework/db/ActiveRecordTest.php index f29e45b9d4..ba4eae1079 100644 --- a/tests/unit/framework/db/ActiveRecordTest.php +++ b/tests/unit/framework/db/ActiveRecordTest.php @@ -409,6 +409,11 @@ class ActiveRecordTest extends DatabaseTestCase 'orders' => function ($q) { $q->orderBy([]); } ])->one(); $this->assertEquals(1, $customer->id); + $order = Order::find()->joinWith([ + 'items' => function ($q) { + $q->from(['items' => 'tbl_item']); + }, + ])->one(); } public function testJoinWithAndScope()