예제 #1
0
 /**
  * Walks down a SelectStatement AST node, wrapping it in a COUNT (SELECT DISTINCT)
  *
  * Note that the ORDER BY clause is not removed. Many SQL implementations (e.g. MySQL)
  * are able to cache subqueries. By keeping the ORDER BY clause intact, the limitSubQuery
  * that will most likely be executed next can be read from the native SQL cache.
  *
  * @param SelectStatement $AST
  * @return string
  */
 public function walkSelectStatement(SelectStatement $AST)
 {
     $sql = parent::walkSelectStatement($AST);
     // Find out the SQL alias of the identifier column of the root entity
     // It may be possible to make this work with multiple root entities but that
     // would probably require issuing multiple queries or doing a UNION SELECT
     // so for now, It's not supported.
     // Get the root entity and alias from the AST fromClause
     $from = $AST->fromClause->identificationVariableDeclarations;
     if (count($from) > 1) {
         throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
     }
     $rootClass = $from[0]->rangeVariableDeclaration->abstractSchemaName;
     $rootAlias = $from[0]->rangeVariableDeclaration->aliasIdentificationVariable;
     // Get the identity properties from the metadata
     $rootIdentifier = $this->queryComponents[$rootAlias]['metadata']->identifier;
     // For every identifier, find out the SQL alias by combing through the ResultSetMapping
     $sqlIdentifier = array();
     foreach ($rootIdentifier as $property) {
         foreach (array_keys($this->rsm->fieldMappings, $property) as $alias) {
             if ($this->rsm->columnOwnerMap[$alias] == $rootAlias) {
                 $sqlIdentifier[$property] = $alias;
             }
         }
     }
     if (count($rootIdentifier) != count($sqlIdentifier)) {
         throw new \RuntimeException(sprintf('Not all identifier properties can be found in the ResultSetMapping: %s', implode(', ', array_diff($rootIdentifier, array_keys($sqlIdentifier)))));
     }
     // Build the counter query
     return sprintf('SELECT %s AS _dctrn_count FROM (SELECT DISTINCT %s FROM (%s) AS _dctrn_result) AS _dctrn_table', $this->platform->getCountExpression('*'), implode(', ', $sqlIdentifier), $sql);
 }