1
0
mirror of synced 2024-12-13 22:56:04 +03:00

Major optimizations in SqlWalker code, reducing overhead, reducing lookahead checks.

This commit is contained in:
Guilherme Blanco 2011-11-03 02:44:50 -02:00
parent 058242fa27
commit 3c31d88810
3 changed files with 235 additions and 328 deletions

View File

@ -47,6 +47,11 @@ class QueryException extends \Doctrine\ORM\ORMException
return new self('[Semantical Error] ' . $message);
}
public static function invalidLockMode()
{
return new self('Invalid lock mode hint provided.');
}
public static function invalidParameterType($expected, $received)
{
return new self('Invalid parameter type, ' . $received . ' given, but ' . $expected . ' expected.');

View File

@ -252,34 +252,40 @@ class SqlWalker implements TreeWalker
// INNER JOIN parent class tables
foreach ($class->parentClasses as $parentClassName) {
$parentClass = $this->_em->getClassMetadata($parentClassName);
$tableAlias = $this->getSQLTableAlias($parentClass->getTableName(), $dqlAlias);
$tableAlias = $this->getSQLTableAlias($parentClass->getTableName(), $dqlAlias);
// If this is a joined association we must use left joins to preserve the correct result.
$sql .= isset($this->_queryComponents[$dqlAlias]['relation']) ? ' LEFT ' : ' INNER ';
$sql .= 'JOIN ' . $parentClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
$first = true;
$sqlParts = array();
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
$sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
}
$sql .= implode(' AND ', $sqlParts);
}
// LEFT JOIN subclass tables, if partial objects disallowed.
if ( ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
$tableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
$first = true;
// Ignore subclassing inclusion if partial objects is disallowed
if ($this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
return $sql;
}
// LEFT JOIN child class tables
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
$tableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
foreach ($class->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= ' LEFT JOIN ' . $subClass->getQuotedTableName($this->_platform) . ' ' . $tableAlias . ' ON ';
$sql .= $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
}
$sqlParts = array();
foreach ($subClass->getQuotedIdentifierColumnNames($this->_platform) as $columnName) {
$sqlParts[] = $baseTableAlias . '.' . $columnName . ' = ' . $tableAlias . '.' . $columnName;
}
$sql .= implode(' AND ', $sqlParts);
}
return $sql;
@ -287,28 +293,24 @@ class SqlWalker implements TreeWalker
private function _generateOrderedCollectionOrderByItems()
{
$sql = '';
$sqlParts = array();
foreach ($this->_selectedClasses AS $dqlAlias => $class) {
$qComp = $this->_queryComponents[$dqlAlias];
if (isset($qComp['relation']['orderBy'])) {
foreach ($qComp['relation']['orderBy'] AS $fieldName => $orientation) {
$tableName = ($qComp['metadata']->isInheritanceTypeJoined())
? $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName)
: $qComp['metadata']->getTableName();
if ($sql != '') {
$sql .= ', ';
}
$sql .= $this->getSQLTableAlias($tableName, $dqlAlias) . '.'
. $qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform) . ' ' . $orientation;
}
if ( ! isset($qComp['relation']['orderBy'])) continue;
foreach ($qComp['relation']['orderBy'] AS $fieldName => $orientation) {
$columnName = $qComp['metadata']->getQuotedColumnName($fieldName, $this->_platform);
$tableName = ($qComp['metadata']->isInheritanceTypeJoined())
? $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName)
: $qComp['metadata']->getTableName();
$sqlParts[] = $this->getSQLTableAlias($tableName, $dqlAlias) . '.' . $columnName . ' ' . $orientation;
}
}
return $sql;
return implode(', ', $sqlParts);
}
/**
@ -319,36 +321,31 @@ class SqlWalker implements TreeWalker
*/
private function _generateDiscriminatorColumnConditionSQL(array $dqlAliases)
{
$encapsulate = false;
$sql = '';
$sqlParts = array();
foreach ($dqlAliases as $dqlAlias) {
$class = $this->_queryComponents[$dqlAlias]['metadata'];
if ($class->isInheritanceTypeSingleTable()) {
$conn = $this->_em->getConnection();
$values = array();
if ( ! $class->isInheritanceTypeSingleTable()) continue;
$conn = $this->_em->getConnection();
$values = array();
if ($class->discriminatorValue !== null) { // discrimnators can be 0
$values[] = $conn->quote($class->discriminatorValue);
}
foreach ($class->subClasses as $subclassName) {
$values[] = $conn->quote($this->_em->getClassMetadata($subclassName)->discriminatorValue);
}
if ($sql != '') {
$sql .= ' AND ';
$encapsulate = true;
}
$sql .= ($sql != '' ? ' AND ' : '')
. (($this->_useSqlTableAliases) ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' : '')
. $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')';
if ($class->discriminatorValue !== null) { // discrimnators can be 0
$values[] = $conn->quote($class->discriminatorValue);
}
foreach ($class->subClasses as $subclassName) {
$values[] = $conn->quote($this->_em->getClassMetadata($subclassName)->discriminatorValue);
}
$sqlParts[] = (($this->_useSqlTableAliases) ? $this->getSQLTableAlias($class->getTableName(), $dqlAlias) . '.' : '')
. $class->discriminatorColumn['name'] . ' IN (' . implode(', ', $values) . ')';
}
return ($encapsulate) ? '(' . $sql . ')' : $sql;
$sql = implode(' AND ', $sqlParts);
return (count($sqlParts) > 1) ? '(' . $sql . ')' : $sql;
}
/**
@ -375,16 +372,25 @@ class SqlWalker implements TreeWalker
);
if (($lockMode = $this->_query->getHint(Query::HINT_LOCK_MODE)) !== false) {
if ($lockMode == LockMode::PESSIMISTIC_READ) {
$sql .= ' ' . $this->_platform->getReadLockSQL();
} else if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
$sql .= ' ' . $this->_platform->getWriteLockSQL();
} else if ($lockMode == LockMode::OPTIMISTIC) {
foreach ($this->_selectedClasses AS $class) {
if ( ! $class->isVersioned) {
throw \Doctrine\ORM\OptimisticLockException::lockFailed($class->name);
switch ($lockMode) {
case LockMode::PESSIMISTIC_READ:
$sql .= ' ' . $this->_platform->getReadLockSQL();
break;
case LockMode::PESSIMISTIC_WRITE:
$sql .= ' ' . $this->_platform->getWriteLockSQL();
break;
case LockMode::PESSIMISTIC_OPTIMISTIC:
foreach ($this->_selectedClasses AS $class) {
if ( ! $class->isVersioned) {
throw \Doctrine\ORM\OptimisticLockException::lockFailed($class->name);
}
}
}
break;
default:
throw \Doctrine\ORM\Query\QueryException::invalidLockMode();
}
}
@ -529,8 +535,8 @@ class SqlWalker implements TreeWalker
if ($class->isInheritanceTypeSingleTable() || $class->isInheritanceTypeJoined()) {
// Add discriminator columns to SQL
$rootClass = $this->_em->getClassMetadata($class->rootEntityName);
$tblAlias = $this->getSQLTableAlias($rootClass->getTableName(), $dqlAlias);
$rootClass = $this->_em->getClassMetadata($class->rootEntityName);
$tblAlias = $this->getSQLTableAlias($rootClass->getTableName(), $dqlAlias);
$discrColumn = $rootClass->discriminatorColumn;
$columnAlias = $this->getSQLColumnAlias($discrColumn['name']);
@ -538,44 +544,44 @@ class SqlWalker implements TreeWalker
$this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias);
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']);
}
// Add foreign key columns to SQL, if necessary
if ( ! $addMetaColumns) continue;
// Add foreign key columns of class and also parent classes
foreach ($class->associationMappings as $assoc) {
if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) continue;
// Add foreign key columns to SQL, if necessary
if ($addMetaColumns) {
//FIXME: Include foreign key columns of child classes also!!??
foreach ($class->associationMappings as $assoc) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
if (isset($assoc['inherited'])) {
$owningClass = $this->_em->getClassMetadata($assoc['inherited']);
$sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias);
} else {
$sqlTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
}
$owningClass = (isset($assoc['inherited'])) ? $this->_em->getClassMetadata($assoc['inherited']) : $class;
$sqlTableAlias = $this->getSQLTableAlias($owningClass->getTableName(), $dqlAlias);
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $this->getSQLColumnAlias($srcColumn);
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $this->getSQLColumnAlias($srcColumn);
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
}
}
}
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
}
} else {
// Add foreign key columns to SQL, if necessary
if ($addMetaColumns) {
$sqlTableAlias = $this->getSQLTableAlias($class->getTableName(), $dqlAlias);
}
// Add foreign key columns of subclasses
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
$sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
foreach ($class->associationMappings as $assoc) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $this->getSQLColumnAlias($srcColumn);
foreach ($subClass->associationMappings as $assoc) {
// Skip if association is inherited
if (isset($assoc['inherited'])) continue;
if ( ! ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE)) continue;
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
$columnAlias = $this->getSQLColumnAlias($srcColumn);
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
$sqlSelectExpressions[] = $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn, (isset($assoc['id']) && $assoc['id'] === true));
}
}
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn);
}
}
}
@ -654,15 +660,13 @@ class SqlWalker implements TreeWalker
*/
public function walkOrderByClause($orderByClause)
{
$colSql = $this->_generateOrderedCollectionOrderByItems();
if ($colSql != '') {
$colSql = ", ".$colSql;
$orderByItems = array_map(array($this, 'walkOrderByItem'), $orderByClause->orderByItems);
if (($collectionOrderByItems = $this->_generateOrderedCollectionOrderByItems()) !== '') {
$orderByItems = array_merge($orderByItems, (array) $collectionOrderByItems);
}
// OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
return ' ORDER BY ' . implode(
', ', array_map(array($this, 'walkOrderByItem'), $orderByClause->orderByItems)
) . $colSql;
return ' ORDER BY ' . implode(', ', $orderByItems);
}
/**
@ -673,16 +677,10 @@ class SqlWalker implements TreeWalker
*/
public function walkOrderByItem($orderByItem)
{
$sql = '';
$expr = $orderByItem->expression;
if ($expr instanceof AST\PathExpression) {
$sql = $this->walkPathExpression($expr);
} else {
$columnName = $this->_queryComponents[$expr]['token']['value'];
$sql = $this->_scalarResultAliasMap[$columnName];
}
$sql = ($expr instanceof AST\PathExpression)
? $this->walkPathExpression($expr)
: $this->_scalarResultAliasMap[$this->_queryComponents[$expr]['token']['value']];
return $sql . ' ' . strtoupper($orderByItem->type);
}
@ -706,22 +704,11 @@ class SqlWalker implements TreeWalker
*/
public function walkJoinVariableDeclaration($joinVarDecl)
{
$join = $joinVarDecl->join;
$join = $joinVarDecl->join;
$joinType = $join->joinType;
if ($joinVarDecl->indexBy) {
// For Many-To-One or One-To-One associations this obviously makes no sense, but is ignored silently.
$this->_rsm->addIndexBy(
$joinVarDecl->indexBy->simpleStateFieldPathExpression->identificationVariable,
$joinVarDecl->indexBy->simpleStateFieldPathExpression->field
);
}
if ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) {
$sql = ' LEFT JOIN ';
} else {
$sql = ' INNER JOIN ';
}
$sql = ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER)
? ' LEFT JOIN '
: ' INNER JOIN ';
$joinAssocPathExpr = $join->joinAssociationPathExpression;
$joinedDqlAlias = $join->aliasIdentificationVariable;
@ -737,10 +724,8 @@ class SqlWalker implements TreeWalker
// Ensure we got the owning side, since it has all mapping info
$assoc = ( ! $relation['isOwningSide']) ? $targetClass->associationMappings[$relation['mappedBy']] : $relation;
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true) {
if ($relation['type'] == ClassMetadata::ONE_TO_MANY || $relation['type'] == ClassMetadata::MANY_TO_MANY) {
throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
}
if ($this->_query->getHint(Query::HINT_INTERNAL_ITERATION) == true && $relation['type'] & ClassMetadata::TO_MANY) {
throw QueryException::iterateWithFetchJoinNotAllowed($assoc);
}
if ($joinVarDecl->indexBy) {
@ -757,7 +742,6 @@ class SqlWalker implements TreeWalker
// be the owning side and previously we ensured that $assoc is always the owning side of the associations.
// The owning side is necessary at this point because only it contains the JoinColumn information.
if ($assoc['type'] & ClassMetadata::TO_ONE) {
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
$first = true;
@ -984,199 +968,133 @@ class SqlWalker implements TreeWalker
$expr = $selectExpression->expression;
$hidden = $selectExpression->hiddenAliasResultVariable;
if ($expr instanceof AST\PathExpression) {
if ($expr->type !== AST\PathExpression::TYPE_STATE_FIELD) {
throw QueryException::invalidPathExpression($expr->type);
}
$fieldName = $expr->field;
$dqlAlias = $expr->identificationVariable;
$qComp = $this->_queryComponents[$dqlAlias];
$class = $qComp['metadata'];
$resultAlias = ( ! $selectExpression->fieldIdentificationVariable)
? $fieldName
: $selectExpression->fieldIdentificationVariable;
$tableName = ($class->isInheritanceTypeJoined())
? $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName)
: $class->getTableName();
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
$columnName = $class->getQuotedColumnName($fieldName, $this->_platform);
$columnAlias = $this->getSQLColumnAlias($columnName);
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
$this->_scalarFields[$dqlAlias][$fieldName] = $columnAlias;
}
} else if ($expr instanceof AST\AggregateExpression) {
if ( ! $selectExpression->fieldIdentificationVariable) {
$resultAlias = $this->_scalarResultCounter++;
} else {
$resultAlias = $selectExpression->fieldIdentificationVariable;
}
$columnAlias = $this->getSQLColumnAlias('sclr');
$sql .= $this->walkAggregateExpression($expr) . ' AS ' . $columnAlias;
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
}
} else if ($expr instanceof AST\Subselect) {
if ( ! $selectExpression->fieldIdentificationVariable) {
$resultAlias = $this->_scalarResultCounter++;
} else {
$resultAlias = $selectExpression->fieldIdentificationVariable;
}
$columnAlias = $this->getSQLColumnAlias('sclr');
$sql .= '(' . $this->walkSubselect($expr) . ') AS '.$columnAlias;
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
}
} else if ($expr instanceof AST\Functions\FunctionNode) {
if ( ! $selectExpression->fieldIdentificationVariable) {
$resultAlias = $this->_scalarResultCounter++;
} else {
$resultAlias = $selectExpression->fieldIdentificationVariable;
}
$columnAlias = $this->getSQLColumnAlias('sclr');
$sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias;
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
}
} else if (
$expr instanceof AST\SimpleArithmeticExpression ||
$expr instanceof AST\ArithmeticTerm ||
$expr instanceof AST\ArithmeticFactor ||
$expr instanceof AST\ArithmeticPrimary ||
$expr instanceof AST\Literal
) {
if ( ! $selectExpression->fieldIdentificationVariable) {
$resultAlias = $this->_scalarResultCounter++;
} else {
$resultAlias = $selectExpression->fieldIdentificationVariable;
}
$columnAlias = $this->getSQLColumnAlias('sclr');
if ($expr instanceof AST\Literal) {
$sql .= $this->walkLiteral($expr) . ' AS ' .$columnAlias;
} else {
$sql .= $this->walkSimpleArithmeticExpression($expr) . ' AS ' . $columnAlias;
}
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
}
} else if (
$expr instanceof AST\NullIfExpression ||
$expr instanceof AST\CoalesceExpression ||
$expr instanceof AST\GeneralCaseExpression ||
$expr instanceof AST\SimpleCaseExpression
) {
if ( ! $selectExpression->fieldIdentificationVariable) {
$resultAlias = $this->_scalarResultCounter++;
} else {
$resultAlias = $selectExpression->fieldIdentificationVariable;
}
$columnAlias = $this->getSQLColumnAlias('sclr');
$sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias;
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
}
} else {
// IdentificationVariable or PartialObjectExpression
if ($expr instanceof AST\PartialObjectExpression) {
$dqlAlias = $expr->identificationVariable;
$partialFieldSet = $expr->partialFieldSet;
} else {
$dqlAlias = $expr;
$partialFieldSet = array();
}
$queryComp = $this->_queryComponents[$dqlAlias];
$class = $queryComp['metadata'];
if ( ! isset($this->_selectedClasses[$dqlAlias])) {
$this->_selectedClasses[$dqlAlias] = $class;
}
$beginning = true;
// Select all fields from the queried class
foreach ($class->fieldMappings as $fieldName => $mapping) {
if ($partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
continue;
switch (true) {
case ($expr instanceof AST\PathExpression):
if ($expr->type !== AST\PathExpression::TYPE_STATE_FIELD) {
throw QueryException::invalidPathExpression($expr->type);
}
$tableName = (isset($mapping['inherited']))
? $this->_em->getClassMetadata($mapping['inherited'])->getTableName()
$fieldName = $expr->field;
$dqlAlias = $expr->identificationVariable;
$qComp = $this->_queryComponents[$dqlAlias];
$class = $qComp['metadata'];
$resultAlias = $selectExpression->fieldIdentificationVariable ?: $fieldName;
$tableName = ($class->isInheritanceTypeJoined())
? $this->_em->getUnitOfWork()->getEntityPersister($class->name)->getOwningTable($fieldName)
: $class->getTableName();
if ($beginning) $beginning = false; else $sql .= ', ';
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $class->getQuotedColumnName($fieldName, $this->_platform)
. ' AS ' . $columnAlias;
$columnName = $class->getQuotedColumnName($fieldName, $this->_platform);
$columnAlias = $this->getSQLColumnAlias($columnName);
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
}
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
$this->_scalarFields[$dqlAlias][$fieldName] = $columnAlias;
}
break;
case ($expr instanceof AST\AggregateExpression):
case ($expr instanceof AST\Functions\FunctionNode):
case ($expr instanceof AST\SimpleArithmeticExpression):
case ($expr instanceof AST\ArithmeticTerm):
case ($expr instanceof AST\ArithmeticFactor):
case ($expr instanceof AST\ArithmeticPrimary):
case ($expr instanceof AST\Literal):
case ($expr instanceof AST\NullIfExpression):
case ($expr instanceof AST\CoalesceExpression):
case ($expr instanceof AST\GeneralCaseExpression):
case ($expr instanceof AST\SimpleCaseExpression):
$columnAlias = $this->getSQLColumnAlias('sclr');
$resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
$sql .= $expr->dispatch($this) . ' AS ' . $columnAlias;
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
// Add any additional fields of subclasses (excluding inherited fields)
// 1) on Single Table Inheritance: always, since its marginal overhead
// 2) on Class Table Inheritance only if partial objects are disallowed,
// since it requires outer joining subtables.
if ($class->isInheritanceTypeSingleTable() || ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
$sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
}
break;
case ($expr instanceof AST\Subselect):
$columnAlias = $this->getSQLColumnAlias('sclr');
$resultAlias = $selectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
$sql .= '(' . $this->walkSubselect($expr) . ') AS '.$columnAlias;
$this->_scalarResultAliasMap[$resultAlias] = $columnAlias;
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['inherited']) || $partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
continue;
}
if ( ! $hidden) {
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
}
break;
default:
// IdentificationVariable or PartialObjectExpression
if ($expr instanceof AST\PartialObjectExpression) {
$dqlAlias = $expr->identificationVariable;
$partialFieldSet = $expr->partialFieldSet;
} else {
$dqlAlias = $expr;
$partialFieldSet = array();
}
if ($beginning) $beginning = false; else $sql .= ', ';
$queryComp = $this->_queryComponents[$dqlAlias];
$class = $queryComp['metadata'];
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform)
. ' AS ' . $columnAlias;
if ( ! isset($this->_selectedClasses[$dqlAlias])) {
$this->_selectedClasses[$dqlAlias] = $class;
}
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName);
$beginning = true;
// Select all fields from the queried class
foreach ($class->fieldMappings as $fieldName => $mapping) {
if ($partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
continue;
}
// Add join columns (foreign keys) of the subclass
//TODO: Probably better do this in walkSelectClause to honor the INCLUDE_META_COLUMNS hint
foreach ($subClass->associationMappings as $fieldName => $assoc) {
if ($assoc['isOwningSide'] && $assoc['type'] & ClassMetadata::TO_ONE && ! isset($assoc['inherited'])) {
foreach ($assoc['targetToSourceKeyColumns'] as $srcColumn) {
if ($beginning) $beginning = false; else $sql .= ', ';
$tableName = (isset($mapping['inherited']))
? $this->_em->getClassMetadata($mapping['inherited'])->getTableName()
: $class->getTableName();
$columnAlias = $this->getSQLColumnAlias($srcColumn);
$sql .= $sqlTableAlias . '.' . $srcColumn . ' AS ' . $columnAlias;
if ($beginning) $beginning = false; else $sql .= ', ';
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn);
$sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias);
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $class->getQuotedColumnName($fieldName, $this->_platform)
. ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name);
}
// Add any additional fields of subclasses (excluding inherited fields)
// 1) on Single Table Inheritance: always, since its marginal overhead
// 2) on Class Table Inheritance only if partial objects are disallowed,
// since it requires outer joining subtables.
if ($class->isInheritanceTypeSingleTable() || ! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
$sqlTableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['inherited']) || $partialFieldSet && !in_array($fieldName, $partialFieldSet)) {
continue;
}
if ($beginning) $beginning = false; else $sql .= ', ';
$columnAlias = $this->getSQLColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform)
. ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName);
}
}
}
}
}
return $sql;
@ -1302,27 +1220,11 @@ class SqlWalker implements TreeWalker
break;
case ($expr instanceof AST\Functions\FunctionNode):
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
$columnAlias = $this->getSQLColumnAlias('sclr');
$this->_scalarResultAliasMap[$alias] = $columnAlias;
$sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias;
break;
case ($expr instanceof AST\SimpleArithmeticExpression):
case ($expr instanceof AST\ArithmeticTerm):
case ($expr instanceof AST\ArithmeticFactor):
case ($expr instanceof AST\ArithmeticPrimary):
case ($expr instanceof AST\Literal):
$alias = $simpleSelectExpression->fieldIdentificationVariable ?: $this->_scalarResultCounter++;
$columnAlias = $this->getSQLColumnAlias('sclr');
$this->_scalarResultAliasMap[$alias] = $columnAlias;
$sql .= $this->walkSimpleArithmeticExpression($expr) . ' AS ' . $columnAlias;
break;
case ($expr instanceof AST\NullIfExpression):
case ($expr instanceof AST\CoalesceExpression):
case ($expr instanceof AST\GeneralCaseExpression):
@ -1332,7 +1234,7 @@ class SqlWalker implements TreeWalker
$columnAlias = $this->getSQLColumnAlias('sclr');
$this->_scalarResultAliasMap[$alias] = $columnAlias;
$sql .= $this->walkCaseExpression($expr) . ' AS ' . $columnAlias;
$sql .= $expr->dispatch($this) . ' AS ' . $columnAlias;
break;
default: // IdentificationVariable

View File

@ -563,7 +563,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
$this->_em->getClassMetadata(get_class($person))->setIdentifierValues($person, array('id' => 101));
$q3->setParameter('param', $person);
$this->assertEquals(
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c1_.car_id AS car_id3, c2_.salary AS salary4, c2_.department AS department5, c2_.startDate AS startDate6, c0_.discr AS discr7, c0_.spouse_id AS spouse_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id WHERE EXISTS (SELECT 1 FROM company_persons_friends c3_ INNER JOIN company_persons c4_ ON c3_.friend_id = c4_.id WHERE c3_.person_id = c0_.id AND c4_.id = ?)',
$q3->getSql()
);
}
@ -1120,7 +1120,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertSqlGeneration(
'SELECT p FROM Doctrine\Tests\Models\Company\CompanyPerson p',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c1_.car_id AS car_id3, c2_.salary AS salary4, c2_.department AS department5, c2_.startDate AS startDate6, c0_.discr AS discr7, c0_.spouse_id AS spouse_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c1_.car_id AS car_id8 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id',
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
);
}
@ -1144,7 +1144,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertSqlGeneration(
'SELECT e FROM Doctrine\Tests\Models\Company\CompanyEmployee e',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c2_.car_id AS car_id6, c0_.discr AS discr7, c0_.spouse_id AS spouse_id8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id',
'SELECT c0_.id AS id0, c0_.name AS name1, c1_.salary AS salary2, c1_.department AS department3, c1_.startDate AS startDate4, c2_.title AS title5, c0_.discr AS discr6, c0_.spouse_id AS spouse_id7, c2_.car_id AS car_id8 FROM company_employees c1_ INNER JOIN company_persons c0_ ON c1_.id = c0_.id LEFT JOIN company_managers c2_ ON c1_.id = c2_.id',
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
);
}
@ -1264,7 +1264,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertSqlGeneration(
'SELECT p, pp FROM Doctrine\Tests\Models\Company\CompanyPerson p JOIN p.spouse pp',
"SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c1_.car_id AS car_id3, c2_.salary AS salary4, c2_.department AS department5, c2_.startDate AS startDate6, c3_.id AS id7, c3_.name AS name8, c4_.title AS title9, c4_.car_id AS car_id10, c5_.salary AS salary11, c5_.department AS department12, c5_.startDate AS startDate13, c0_.discr AS discr14, c0_.spouse_id AS spouse_id15, c3_.discr AS discr16, c3_.spouse_id AS spouse_id17 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ ON c0_.spouse_id = c3_.id LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id",
"SELECT c0_.id AS id0, c0_.name AS name1, c1_.title AS title2, c2_.salary AS salary3, c2_.department AS department4, c2_.startDate AS startDate5, c3_.id AS id6, c3_.name AS name7, c4_.title AS title8, c5_.salary AS salary9, c5_.department AS department10, c5_.startDate AS startDate11, c0_.discr AS discr12, c0_.spouse_id AS spouse_id13, c1_.car_id AS car_id14, c3_.discr AS discr15, c3_.spouse_id AS spouse_id16, c4_.car_id AS car_id17 FROM company_persons c0_ LEFT JOIN company_managers c1_ ON c0_.id = c1_.id LEFT JOIN company_employees c2_ ON c0_.id = c2_.id INNER JOIN company_persons c3_ ON c0_.spouse_id = c3_.id LEFT JOIN company_managers c4_ ON c3_.id = c4_.id LEFT JOIN company_employees c5_ ON c3_.id = c5_.id",
array(Query::HINT_FORCE_PARTIAL_LOAD => false)
);
}