/** * Walks down a SelectExpression AST node and generates the corresponding SQL. * * @param SelectExpression $selectExpression * @return string The SQL. */ public function walkSelectExpression($selectExpression) { $sql = ''; $expr = $selectExpression->expression; if ($expr instanceof AST\PathExpression) { if ($expr->type == AST\PathExpression::TYPE_STATE_FIELD) { $parts = $expr->parts; $fieldName = array_pop($parts); $dqlAlias = $expr->identificationVariable . (!empty($parts) ? '.' . implode('.', $parts) : ''); $qComp = $this->_queryComponents[$dqlAlias]; $class = $qComp['metadata']; if (!isset($this->_selectedClasses[$dqlAlias])) { $this->_selectedClasses[$dqlAlias] = $class; } $sqlTableAlias = $this->getSqlTableAlias($class->getTableName(), $dqlAlias); $columnName = $class->getQuotedColumnName($fieldName, $this->_platform); $columnAlias = $this->getSqlColumnAlias($class->columnNames[$fieldName]); $sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias; $columnAlias = $this->_platform->getSqlResultCasing($columnAlias); $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name); } else { throw DoctrineException::invalidPathExpression($expr->type); } } else { if ($expr instanceof AST\AggregateExpression) { if (!$selectExpression->fieldIdentificationVariable) { $resultAlias = $this->_scalarResultCounter++; } else { $resultAlias = $selectExpression->fieldIdentificationVariable; } $columnAlias = 'sclr' . $this->_aliasCounter++; $sql .= $this->walkAggregateExpression($expr) . ' AS ' . $columnAlias; $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; $columnAlias = $this->_platform->getSqlResultCasing($columnAlias); $this->_rsm->addScalarResult($columnAlias, $resultAlias); } else { if ($expr instanceof AST\Subselect) { $sql .= $this->walkSubselect($expr); } else { if ($expr instanceof AST\Functions\FunctionNode) { if (!$selectExpression->fieldIdentificationVariable) { $resultAlias = $this->_scalarResultCounter++; } else { $resultAlias = $selectExpression->fieldIdentificationVariable; } $columnAlias = 'sclr' . $this->_aliasCounter++; $sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias; $this->_scalarResultAliasMap[$resultAlias] = $columnAlias; $columnAlias = $this->_platform->getSqlResultCasing($columnAlias); $this->_rsm->addScalarResult($columnAlias, $resultAlias); } else { // $expr == IdentificationVariable $dqlAlias = $expr; $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 (isset($mapping['inherited'])) { $tableName = $this->_em->getClassMetadata($mapping['inherited'])->primaryTable['name']; } else { $tableName = $class->primaryTable['name']; } 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; $columnAlias = $this->_platform->getSqlResultCasing($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->primaryTable['name'], $dqlAlias); foreach ($subClass->fieldMappings as $fieldName => $mapping) { if (isset($mapping['inherited'])) { continue; } if ($beginning) { $beginning = false; } else { $sql .= ', '; } $columnAlias = $this->getSqlColumnAlias($mapping['columnName']); $sql .= $sqlTableAlias . '.' . $subClass->getQuotedColumnName($fieldName, $this->_platform) . ' AS ' . $columnAlias; $columnAlias = $this->_platform->getSqlResultCasing($columnAlias); $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName); } // 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->isOneToOne() && !isset($subClass->inheritedAssociationFields[$fieldName])) { foreach ($assoc->targetToSourceKeyColumns as $srcColumn) { if ($beginning) { $beginning = false; } else { $sql .= ', '; } $columnAlias = $this->getSqlColumnAlias($srcColumn); $sql .= $sqlTableAlias . '.' . $assoc->getQuotedJoinColumnName($srcColumn, $this->_platform) . ' AS ' . $columnAlias; $this->_rsm->addMetaResult($dqlAlias, $this->_platform->getSqlResultCasing($columnAlias), $srcColumn); } } } } } } } } } return $sql; }