/**
  * 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);
 }
 /**
  * Walks down a SelectStatement AST node, wrapping it in a SELECT DISTINCT
  *
  * @param SelectStatement $AST
  * @return string
  */
 public function walkSelectStatement(SelectStatement $AST)
 {
     $innerSql = 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");
     }
     $rootAlias = $from[0]->rangeVariableDeclaration->aliasIdentificationVariable;
     $rootClass = $this->queryComponents[$rootAlias]['metadata'];
     $rootIdentifier = $rootClass->identifier;
     // For every identifier, find out the SQL alias by combing through the ResultSetMapping
     $sqlIdentifier = array();
     foreach ($rootIdentifier as $property) {
         if (isset($rootClass->fieldMappings[$property])) {
             foreach (array_keys($this->rsm->fieldMappings, $property) as $alias) {
                 if ($this->rsm->columnOwnerMap[$alias] == $rootAlias) {
                     $sqlIdentifier[$property] = $alias;
                 }
             }
         }
         if (isset($rootClass->associationMappings[$property])) {
             $joinColumn = $rootClass->associationMappings[$property]['joinColumns'][0]['name'];
             foreach (array_keys($this->rsm->metaMappings, $joinColumn) 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
     $sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result', implode(', ', $sqlIdentifier), $innerSql);
     if ($this->platform instanceof PostgreSqlPlatform) {
         //http://www.doctrine-project.org/jira/browse/DDC-1958
         $this->getPostgresqlSql($AST, $sqlIdentifier, $innerSql, $sql);
     }
     // Apply the limit and offset
     $sql = $this->platform->modifyLimitQuery($sql, $this->maxResults, $this->firstResult);
     // Add the columns to the ResultSetMapping. It's not really nice but
     // it works. Preferably I'd clear the RSM or simply create a new one
     // but that is not possible from inside the output walker, so we dirty
     // up the one we have.
     foreach ($sqlIdentifier as $property => $alias) {
         $this->rsm->addScalarResult($alias, $property);
     }
     return $sql;
 }
 /**
  * {@inheritDoc}
  */
 public function walkSelectStatement(SelectStatement $AST)
 {
     $result = parent::walkSelectStatement($AST);
     if (!count($this->translatedComponents)) {
         return $result;
     }
     $hydrationMode = $this->getQuery()->getHydrationMode();
     if ($hydrationMode === Query::HYDRATE_OBJECT) {
         $this->getQuery()->setHydrationMode(self::HYDRATE_OBJECT_TRANSLATION);
         $this->getEntityManager()->getConfiguration()->addCustomHydrationMode(self::HYDRATE_OBJECT_TRANSLATION, 'Gedmo\\Translatable\\Hydrator\\ORM\\ObjectHydrator');
         $this->getQuery()->setHint(Query::HINT_REFRESH, true);
     } elseif ($hydrationMode === Query::HYDRATE_SIMPLEOBJECT) {
         $this->getQuery()->setHydrationMode(self::HYDRATE_SIMPLE_OBJECT_TRANSLATION);
         $this->getEntityManager()->getConfiguration()->addCustomHydrationMode(self::HYDRATE_SIMPLE_OBJECT_TRANSLATION, 'Gedmo\\Translatable\\Hydrator\\ORM\\SimpleObjectHydrator');
         $this->getQuery()->setHint(Query::HINT_REFRESH, true);
     }
     return $result;
 }
 public function __construct(SelectStatement $AST, SqlWalker $sqlWalker)
 {
     $this->_sqlStatements = $sqlWalker->walkSelectStatement($AST);
 }
 public function walkSelectStatement(Query\AST\SelectStatement $selectStatement)
 {
     parent::walkSelectStatement($selectStatement);
     $this->setQueryComponent('x', array());
 }
 /**
  * @param SelectStatement $AST
  *
  * @return string
  *
  * @throws \Doctrine\ORM\OptimisticLockException
  * @throws \Doctrine\ORM\Query\QueryException
  */
 private function getInnerSQL(SelectStatement $AST)
 {
     // Set every select expression as visible(hidden = false) to
     // make $AST have scalar mappings properly - this is relevant for referencing selected
     // fields from outside the subquery, for example in the ORDER BY segment
     $hiddens = [];
     foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
         $hiddens[$idx] = $expr->hiddenAliasResultVariable;
         $expr->hiddenAliasResultVariable = false;
     }
     $innerSql = parent::walkSelectStatement($AST);
     // Restore hiddens
     foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
         $expr->hiddenAliasResultVariable = $hiddens[$idx];
     }
     return $innerSql;
 }
 /**
  * {@inheritDoc}
  */
 public function walkSelectStatement(SelectStatement $AST)
 {
     $result = parent::walkSelectStatement($AST);
     if (!count($this->translatedComponents)) {
         return $result;
     }
     $hydrationMode = $this->getQuery()->getHydrationMode();
     if ($this->needsFallback()) {
         // in case if fallback is used and hydration is array, it needs custom hydrator
         if ($hydrationMode === Query::HYDRATE_ARRAY) {
             $this->getQuery()->setHydrationMode(self::HYDRATE_ARRAY_TRANSLATION);
             $this->getEntityManager()->getConfiguration()->addCustomHydrationMode(self::HYDRATE_ARRAY_TRANSLATION, 'Gedmo\\Translatable\\Hydrator\\ORM\\ArrayHydrator');
         }
     }
     $this->getQuery()->setHint(self::HINT_TRANSLATION_LISTENER, $this->listener);
     if ($hydrationMode === Query::HYDRATE_OBJECT) {
         $this->getQuery()->setHydrationMode(self::HYDRATE_OBJECT_TRANSLATION);
         $this->getEntityManager()->getConfiguration()->addCustomHydrationMode(self::HYDRATE_OBJECT_TRANSLATION, 'Gedmo\\Translatable\\Hydrator\\ORM\\ObjectHydrator');
         $this->getQuery()->setHint(Query::HINT_REFRESH, true);
     } elseif ($hydrationMode === Query::HYDRATE_SIMPLEOBJECT) {
         $this->getQuery()->setHydrationMode(self::HYDRATE_SIMPLE_OBJECT_TRANSLATION);
         $this->getEntityManager()->getConfiguration()->addCustomHydrationMode(self::HYDRATE_SIMPLE_OBJECT_TRANSLATION, 'Gedmo\\Translatable\\Hydrator\\ORM\\SimpleObjectHydrator');
         $this->getQuery()->setHint(Query::HINT_REFRESH, true);
     }
     return $result;
 }
 /**
  * Walks down a SelectStatement AST node, wrapping it in a SELECT DISTINCT.
  *
  * @param SelectStatement $AST
  * @param bool $addMissingItemsFromOrderByToSelect
  *
  * @return string
  *
  * @throws \RuntimeException
  */
 public function walkSelectStatement(SelectStatement $AST, $addMissingItemsFromOrderByToSelect = true)
 {
     // We don't want to call this recursively!
     if ($AST->orderByClause instanceof OrderByClause && $addMissingItemsFromOrderByToSelect) {
         // In the case of ordering a query by columns from joined tables, we
         // must add those columns to the select clause of the query BEFORE
         // the SQL is generated.
         $this->addMissingItemsFromOrderByToSelect($AST);
     }
     // Remove order by clause from the inner query
     // It will be re-appended in the outer select generated by this method
     $orderByClause = $AST->orderByClause;
     $AST->orderByClause = null;
     // Set every select expression as visible(hidden = false) to
     // make $AST have scalar mappings properly - this is relevant for referencing selected
     // fields from outside the subquery, for example in the ORDER BY segment
     $hiddens = array();
     foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
         $hiddens[$idx] = $expr->hiddenAliasResultVariable;
         $expr->hiddenAliasResultVariable = false;
     }
     $innerSql = parent::walkSelectStatement($AST);
     // Restore orderByClause
     $AST->orderByClause = $orderByClause;
     // Restore hiddens
     foreach ($AST->selectClause->selectExpressions as $idx => $expr) {
         $expr->hiddenAliasResultVariable = $hiddens[$idx];
     }
     // 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");
     }
     $fromRoot = reset($from);
     $rootAlias = $fromRoot->rangeVariableDeclaration->aliasIdentificationVariable;
     $rootClass = $this->queryComponents[$rootAlias]['metadata'];
     $rootIdentifier = $rootClass->identifier;
     // For every identifier, find out the SQL alias by combing through the ResultSetMapping
     $sqlIdentifier = array();
     foreach ($rootIdentifier as $property) {
         if (isset($rootClass->fieldMappings[$property])) {
             foreach (array_keys($this->rsm->fieldMappings, $property) as $alias) {
                 if ($this->rsm->columnOwnerMap[$alias] == $rootAlias) {
                     $sqlIdentifier[$property] = $alias;
                 }
             }
         }
         if (isset($rootClass->associationMappings[$property])) {
             $joinColumn = $rootClass->associationMappings[$property]['joinColumns'][0]['name'];
             foreach (array_keys($this->rsm->metaMappings, $joinColumn) as $alias) {
                 if ($this->rsm->columnOwnerMap[$alias] == $rootAlias) {
                     $sqlIdentifier[$property] = $alias;
                 }
             }
         }
     }
     if (count($sqlIdentifier) === 0) {
         throw new \RuntimeException('The Paginator does not support Queries which only yield ScalarResults.');
     }
     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
     $sql = sprintf('SELECT DISTINCT %s FROM (%s) dctrn_result', implode(', ', $sqlIdentifier), $innerSql);
     // http://www.doctrine-project.org/jira/browse/DDC-1958
     $sql = $this->preserveSqlOrdering($sqlIdentifier, $innerSql, $sql, $orderByClause);
     // Apply the limit and offset.
     $sql = $this->platform->modifyLimitQuery($sql, $this->maxResults, $this->firstResult);
     // Add the columns to the ResultSetMapping. It's not really nice but
     // it works. Preferably I'd clear the RSM or simply create a new one
     // but that is not possible from inside the output walker, so we dirty
     // up the one we have.
     foreach ($sqlIdentifier as $property => $alias) {
         $this->rsm->addScalarResult($alias, $property);
     }
     return $sql;
 }