Commit 13c0931b by Qiang Xue

Fixes #2880

parent 093f5ebd
......@@ -62,7 +62,7 @@ namespace yii\db;
* If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method.
* These methods may only be called in a relational context. Same is true for [[inverseOf()]], which
* marks a relation as inverse of another relation and [[onCondition()]] which adds a condition that
* is to be added to relational querys join condition.
* is to be added to relational query join condition.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
......@@ -106,6 +106,40 @@ class ActiveQuery extends Query implements ActiveQueryInterface
/**
* @inheritdoc
*/
public function prepareBuild($builder)
{
if (!empty($this->joinWith)) {
$this->buildJoinWith();
$this->joinWith = null; // clean it up to avoid issue https://github.com/yiisoft/yii2/issues/2687
}
if (empty($this->from)) {
/** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass;
$tableName = $modelClass::tableName();
$this->from = [$tableName];
}
if (empty($this->select) && !empty($this->join)) {
foreach ((array)$this->from as $alias => $table) {
if (is_string($alias)) {
$this->select = ["$alias.*"];
} elseif (is_string($table)) {
if (preg_match('/^(.*?)\s+({{\w+}}|\w+)$/', $table, $matches)) {
$alias = $matches[2];
} else {
$alias = $table;
}
$this->select = ["$alias.*"];
}
break;
}
}
}
/**
* @inheritdoc
*/
public function prepareResult($rows)
{
if (empty($rows)) {
......@@ -246,10 +280,6 @@ class ActiveQuery extends Query implements ActiveQueryInterface
}
if ($this->sql === null) {
if (!empty($this->joinWith)) {
$this->buildJoinWith();
$this->joinWith = null; // clean it up to avoid issue https://github.com/yiisoft/yii2/issues/2687
}
list ($sql, $params) = $db->getQueryBuilder()->build($this);
} else {
$sql = $this->sql;
......
......@@ -124,6 +124,16 @@ class Query extends Component implements QueryInterface
}
/**
* Prepares for building SQL.
* This method is called by [[QueryBuilder]] when it starts to build SQL from a query object.
* You may override this method to do some final preparation work when converting a query into a SQL statement.
* @param QueryBuilder $builder
*/
public function prepareBuild($builder)
{
}
/**
* Starts a batch query.
*
* A batch query supports fetching data in batches, which can keep the memory usage under a limit.
......
......@@ -64,12 +64,13 @@ class QueryBuilder extends \yii\base\Object
*/
public function build($query, $params = [])
{
$query->prepareBuild($this);
$params = empty($params) ? $query->params : array_merge($params, $query->params);
list ($select, $from) = $this->adjustSelectFrom($query);
$clauses = [
$this->buildSelect($select, $params, $query->distinct, $query->selectOption),
$this->buildFrom($from, $params),
$this->buildSelect($query->select, $params, $query->distinct, $query->selectOption),
$this->buildFrom($query->from, $params),
$this->buildJoin($query->join, $params),
$this->buildWhere($query->where, $params),
$this->buildGroupBy($query->groupBy),
......@@ -89,44 +90,6 @@ class QueryBuilder extends \yii\base\Object
}
/**
* Adjusts the select and from parts of the query when it is an ActiveQuery.
* When ActiveQuery does not specify "from", or if it is a join query without explicit "select",
* certain adjustments need to be made. This method is put here so that QueryBuilder can
* support sub-queries.
* @param Query $query
* @return array the select and from parts.
*/
protected function adjustSelectFrom($query)
{
$select = $query->select;
$from = $query->from;
if ($query instanceof ActiveQuery && (empty($select) || empty($from))) {
/** @var ActiveRecord $modelClass */
$modelClass = $query->modelClass;
$tableName = $modelClass::tableName();
if (empty($from)) {
$from = [$tableName];
}
if (empty($select) && !empty($query->join)) {
foreach ((array)$from as $alias => $table) {
if (is_string($alias)) {
$select = ["$alias.*"];
} elseif (is_string($table)) {
if (preg_match('/^(.*?)\s+({{\w+}}|\w+)$/', $table, $matches)) {
$alias = $matches[2];
} else {
$alias = $tableName;
}
$select = ["$alias.*"];
}
break;
}
}
}
return [$select, $from];
}
/**
* Creates an INSERT SQL statement.
* For example,
*
......
......@@ -19,7 +19,6 @@ use yii\db\ActiveRecord;
*/
class QueryBuilder extends \yii\db\QueryBuilder
{
private $sql;
/**
......@@ -28,11 +27,10 @@ class QueryBuilder extends \yii\db\QueryBuilder
public function build($query, $params = [])
{
$params = empty($params) ? $query->params : array_merge($params, $query->params);
list ($select, $from) = $this->adjustSelectFrom($query);
$clauses = [
$this->buildSelect($select, $params, $query->distinct, $query->selectOption),
$this->buildFrom($from, $params),
$this->buildSelect($query->select, $params, $query->distinct, $query->selectOption),
$this->buildFrom($query->from, $params),
$this->buildJoin($query->join, $params),
$this->buildWhere($query->where, $params),
$this->buildGroupBy($query->groupBy),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment