Fixed Query not to dig inside Expression

This commit is contained in:
SilverFire - Dmitry Naumenko
2017-12-21 16:16:33 +02:00
parent 7e90962029
commit 8f2cd050af
3 changed files with 33 additions and 34 deletions

View File

@ -8,7 +8,7 @@ Yii Framework 2 Change Log
- Bug #14157: Add support for loading default value `CURRENT_TIMESTAMP` of MySQL `datetime` field (rossoneri) - Bug #14157: Add support for loading default value `CURRENT_TIMESTAMP` of MySQL `datetime` field (rossoneri)
- Bug #15046: Throw an `yii\web\HeadersAlreadySentException` if headers were sent before web response (dmirogin) - Bug #15046: Throw an `yii\web\HeadersAlreadySentException` if headers were sent before web response (dmirogin)
- Enh #3087: Added `yii\helpers\BaseHtml::error()` "errorMethod" option to be able to customize errors display (yanggs07, developeruz) - Enh #3087: Added `yii\helpers\BaseHtml::error()` "errorMethod" option to be able to customize errors display (yanggs07, developeruz)
- Bug #15355: Fixed `yii\db\Query::from()` does not work with `yii\db\Expression` (vladis84) - Bug #15355: Fixed `yii\db\Query::from()` does not work with `yii\db\Expression` (vladis84, silverfire, samdark)
- Bug #8983: Only truncate the original log file for rotation (matthewyang, developeruz) - Bug #8983: Only truncate the original log file for rotation (matthewyang, developeruz)
- Bug #14276: Fixed I18N format with dotted parameters (developeruz) - Bug #14276: Fixed I18N format with dotted parameters (developeruz)
- Bug #14484: Fixed `yii\validators\UniqueValidator` for target classes with a default scope (laszlovl, developeruz) - Bug #14484: Fixed `yii\validators\UniqueValidator` for target classes with a default scope (laszlovl, developeruz)

View File

@ -10,6 +10,7 @@ namespace yii\db;
use Yii; use Yii;
use yii\base\Component; use yii\base\Component;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
/** /**
* Query represents a SELECT SQL statement in a way that is independent of DBMS. * Query represents a SELECT SQL statement in a way that is independent of DBMS.
@ -481,60 +482,57 @@ class Query extends Component implements QueryInterface
// Clean up table names and aliases // Clean up table names and aliases
$cleanedUpTableNames = []; $cleanedUpTableNames = [];
foreach ($tableNames as $alias => $tableName) { foreach ($tableNames as $alias => $tableName) {
$tableNameString = null; if (is_string($tableName) && !is_string($alias)) {
if (is_string($tableName)) {
$tableNameString = $tableName;
} elseif ($tableName instanceof Expression) {
$tableNameString = $tableName->expression;
}
if (!is_string($alias) && $tableNameString !== null) {
$pattern = <<<PATTERN $pattern = <<<PATTERN
~ ~
^ ^
\s* \s*
( (
(?:['"`\[]|{{) (?:['"`\[]|{{)
.*?
(?:['"`\]]|}})
|
\(.*?\)
|
.*?
)
(?:
(?:
\s+
(?:as)?
\s*
)
(
(?:['"`\[]|{{)
.*? .*?
(?:['"`\]]|}}) (?:['"`\]]|}})
| |
\(.*?\)
|
.*? .*?
) )
(?:
(?:
\s+
(?:as)?
\s*
)
(
(?:['"`\[]|{{)
.*?
(?:['"`\]]|}})
|
.*?
)
)? )?
\s* \s*
$ $
~iux ~iux
PATTERN; PATTERN;
if (preg_match($pattern, $tableNameString, $matches)) { if (preg_match($pattern, $tableName, $matches)) {
if (isset($matches[2])) { if (isset($matches[2])) {
list(, $tableNameString, $alias) = $matches; list(, $tableName, $alias) = $matches;
} else { } else {
$tableNameString = $alias = $matches[1]; $tableName = $alias = $matches[1];
} }
} }
} }
if ($tableName instanceof Expression) { if ($tableName instanceof Expression) {
$cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $tableNameString; if (!is_string($alias)) {
throw new InvalidParamException('To use Expression in from() method, pass it in array format with alias.');
}
$cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $tableName;
} elseif ($tableName instanceof self) { } elseif ($tableName instanceof self) {
$cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $tableName; $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $tableName;
} else { } else {
$cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $this->ensureNameQuoted($tableNameString); $cleanedUpTableNames[$this->ensureNameQuoted($alias)] = $this->ensureNameQuoted($tableName);
} }
} }

View File

@ -129,13 +129,14 @@ trait GetTablesAliasTestTrait
public function testGetTableNames_isFromAliasedExpression() public function testGetTableNames_isFromAliasedExpression()
{ {
$query = $this->createQuery(); $query = $this->createQuery();
$query->from = new \yii\db\Expression('(SELECT id FROM user) x'); $expression = new \yii\db\Expression('(SELECT id FROM user)');
$query->from = $expression;
$this->expectException('yii\base\InvalidParamException');
$this->expectExceptionMessage('To use Expression in from() method, pass it in array format with alias.');
$tables = $query->getTablesUsedInFrom(); $tables = $query->getTablesUsedInFrom();
$this->assertEquals([ $this->assertEquals(['{{x}}' => $expression], $tables);
'{{x}}' => '(SELECT id FROM user)',
], $tables);
} }
public function testGetTableNames_isFromAliasedArrayWithExpression() public function testGetTableNames_isFromAliasedArrayWithExpression()