/**
  * @param QueryObjectModel $qom
  *
  * @return string
  */
 public function walkQOMQuery(QueryObjectModel $qom)
 {
     $source = $qom->getSource();
     $selectors = $this->validateSource($source);
     $sourceSql = " " . $this->walkSource($source);
     $constraintSql = '';
     if ($constraint = $qom->getConstraint()) {
         $constraintSql = " AND " . $this->walkConstraint($constraint);
     }
     $orderingSql = '';
     if ($orderings = $qom->getOrderings()) {
         $orderingSql = " " . $this->walkOrderings($orderings);
     }
     $sql = "SELECT " . $this->getColumns($qom);
     $sql .= $sourceSql;
     $sql .= $constraintSql;
     $sql .= $orderingSql;
     $limit = $qom->getLimit();
     $offset = $qom->getOffset();
     if (null !== $offset && null == $limit && ($this->platform instanceof MySqlPlatform || $this->platform instanceof SqlitePlatform)) {
         $limit = PHP_INT_MAX;
     }
     $sql = $this->platform->modifyLimitQuery($sql, $limit, $offset);
     return array($selectors, $this->alias, $sql);
 }
 /**
  * Walks down a SelectStatement AST node, wrapping it in a SELECT DISTINCT.
  * This method is for platforms which DO NOT support ROW_NUMBER.
  *
  * @param SelectStatement $AST
  * @param bool $addMissingItemsFromOrderByToSelect
  *
  * @return string
  *
  * @throws \RuntimeException
  */
 public function walkSelectStatementWithoutRowNumber(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;
     $innerSql = $this->getInnerSQL($AST);
     $sqlIdentifier = $this->getSQLIdentifier($AST);
     // 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);
     }
     // Restore orderByClause
     $AST->orderByClause = $orderByClause;
     return $sql;
 }
 /**
  * Return a list of all revisions.
  *
  * @param int $limit
  * @param int $offset
  * @return Revision[]
  */
 public function findRevisionHistory($limit = 20, $offset = 0)
 {
     $query = $this->platform->modifyLimitQuery("SELECT * FROM " . $this->config->getRevisionTableName() . " ORDER BY id DESC", $limit, $offset);
     $revisionsData = $this->em->getConnection()->fetchAll($query);
     $revisions = array();
     foreach ($revisionsData as $row) {
         $revisions[] = new Revision($row['id'], \DateTime::createFromFormat($this->platform->getDateTimeFormatString(), $row['timestamp']), $row['username']);
     }
     return $revisions;
 }
 /**
  * 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;
 }
 /**
  * Gets the SELECT SQL to select one or more entities by a set of field criteria.
  *
  * @param array $criteria
  * @param AssociationMapping $assoc
  * @param string $orderBy
  * @param int $lockMode
  * @param int $limit
  * @param int $offset
  * @param array $orderBy
  * @return string
  * @todo Refactor: _getSelectSQL(...)
  */
 protected function _getSelectEntitiesSQL(array $criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null, array $orderBy = null)
 {
     $joinSql = $assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY ? $this->_getSelectManyToManyJoinSQL($assoc) : '';
     $conditionSql = $this->_getSelectConditionSQL($criteria, $assoc);
     $orderBy = $assoc !== null && isset($assoc['orderBy']) ? $assoc['orderBy'] : $orderBy;
     $orderBySql = $orderBy ? $this->_getOrderBySQL($orderBy, $this->_getSQLTableAlias($this->_class->name)) : '';
     $lockSql = '';
     if ($lockMode == LockMode::PESSIMISTIC_READ) {
         $lockSql = ' ' . $this->_platform->getReadLockSql();
     } else {
         if ($lockMode == LockMode::PESSIMISTIC_WRITE) {
             $lockSql = ' ' . $this->_platform->getWriteLockSql();
         }
     }
     return $this->_platform->modifyLimitQuery('SELECT ' . $this->_getSelectColumnListSQL() . $this->_platform->appendLockHint(' FROM ' . $this->_class->getQuotedTableName($this->_platform) . ' ' . $this->_getSQLTableAlias($this->_class->name), $lockMode) . $this->_selectJoinSql . $joinSql . ($conditionSql ? ' WHERE ' . $conditionSql : '') . $orderBySql, $limit, $offset) . $lockSql;
 }
Beispiel #6
0
 /**
  * {@inheritdoc}
  */
 public function walkSelectStatement(AST\SelectStatement $AST)
 {
     $sql = $this->walkSelectClause($AST->selectClause);
     $sql .= $this->walkFromClause($AST->fromClause);
     $sql .= $this->walkWhereClause($AST->whereClause);
     $sql .= $AST->groupByClause ? $this->walkGroupByClause($AST->groupByClause) : '';
     $sql .= $AST->havingClause ? $this->walkHavingClause($AST->havingClause) : '';
     if (($orderByClause = $AST->orderByClause) !== null) {
         $sql .= $AST->orderByClause ? $this->walkOrderByClause($AST->orderByClause) : '';
     } else {
         if (($orderBySql = $this->_generateOrderedCollectionOrderByItems()) !== '') {
             $sql .= ' ORDER BY ' . $orderBySql;
         }
     }
     $sql = $this->platform->modifyLimitQuery($sql, $this->query->getMaxResults(), $this->query->getFirstResult());
     if (($lockMode = $this->query->getHint(Query::HINT_LOCK_MODE)) !== false) {
         switch ($lockMode) {
             case LockMode::PESSIMISTIC_READ:
                 $sql .= ' ' . $this->platform->getReadLockSQL();
                 break;
             case LockMode::PESSIMISTIC_WRITE:
                 $sql .= ' ' . $this->platform->getWriteLockSQL();
                 break;
             case LockMode::OPTIMISTIC:
                 foreach ($this->selectedClasses as $selectedClass) {
                     if (!$selectedClass['class']->isVersioned) {
                         throw \Doctrine\ORM\OptimisticLockException::lockFailed($selectedClass['class']->name);
                     }
                 }
                 break;
             case LockMode::NONE:
                 break;
             default:
                 throw \Doctrine\ORM\Query\QueryException::invalidLockMode();
         }
     }
     return $sql;
 }
    /**
     * Gets the SELECT SQL to select one or more entities by a set of field criteria.
     *
     * @param array|\Doctrine\Common\Collections\Criteria $criteria
     * @param array|null                                  $assoc
     * @param int                                         $lockMode
     * @param int|null                                    $limit
     * @param int|null                                    $offset
     * @param array|null                                  $orderBy
     *
     * @return string
     */
    protected function getSelectSQL($criteria, $assoc = null, $lockMode = 0, $limit = null, $offset = null, array $orderBy = null)
    {
        $lockSql    = '';
        $joinSql    = '';
        $orderBySql = '';

        if ($assoc != null && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
            $joinSql = $this->getSelectManyToManyJoinSQL($assoc);
        }

        if (isset($assoc['orderBy'])) {
            $orderBy = $assoc['orderBy'];
        }

        if ($orderBy) {
            $orderBySql = $this->getOrderBySQL($orderBy, $this->getSQLTableAlias($this->class->name));
        }

        $conditionSql = ($criteria instanceof Criteria)
            ? $this->getSelectConditionCriteriaSQL($criteria)
            : $this->getSelectConditionSQL($criteria, $assoc);

        switch ($lockMode) {
            case LockMode::PESSIMISTIC_READ:
                $lockSql = ' ' . $this->platform->getReadLockSql();
                break;

            case LockMode::PESSIMISTIC_WRITE:
                $lockSql = ' ' . $this->platform->getWriteLockSql();
                break;
        }

        $columnList = $this->getSelectColumnsSQL();
        $tableAlias = $this->getSQLTableAlias($this->class->name);
        $filterSql  = $this->generateFilterConditionSQL($this->class, $tableAlias);
        $tableName  = $this->quoteStrategy->getTableName($this->class, $this->platform);

        if ('' !== $filterSql) {
            $conditionSql = $conditionSql 
                ? $conditionSql . ' AND ' . $filterSql
                : $filterSql;
        }

        $select = 'SELECT ' . $columnList;
        $from   = ' FROM ' . $tableName . ' '. $tableAlias;
        $join   = $this->selectJoinSql . $joinSql;
        $where  = ($conditionSql ? ' WHERE ' . $conditionSql : '');
        $lock   = $this->platform->appendLockHint($from, $lockMode);
        $query  = $select
            . $lock
            . $join
            . $where
            . $orderBySql;

        return $this->platform->modifyLimitQuery($query, $limit, $offset) . $lockSql;
    }
 /**
  * {@inheritdoc}
  */
 public function walkSelectStatement(AST\SelectStatement $AST)
 {
     $limit = $this->query->getMaxResults();
     $offset = $this->query->getFirstResult();
     $lockMode = $this->query->getHint(Query::HINT_LOCK_MODE);
     $sql = $this->walkSelectClause($AST->selectClause) . $this->walkFromClause($AST->fromClause) . $this->walkWhereClause($AST->whereClause);
     if ($AST->groupByClause) {
         $sql .= $this->walkGroupByClause($AST->groupByClause);
     }
     if ($AST->havingClause) {
         $sql .= $this->walkHavingClause($AST->havingClause);
     }
     if ($AST->orderByClause) {
         $sql .= $this->walkOrderByClause($AST->orderByClause);
     }
     if (!$AST->orderByClause && ($orderBySql = $this->_generateOrderedCollectionOrderByItems())) {
         $sql .= ' ORDER BY ' . $orderBySql;
     }
     if ($limit !== null || $offset !== null) {
         $sql = $this->platform->modifyLimitQuery($sql, $limit, $offset);
     }
     if ($lockMode === null || $lockMode === false || $lockMode === LockMode::NONE) {
         return $sql;
     }
     if ($lockMode === LockMode::PESSIMISTIC_READ) {
         return $sql . ' ' . $this->platform->getReadLockSQL();
     }
     if ($lockMode === LockMode::PESSIMISTIC_WRITE) {
         return $sql . ' ' . $this->platform->getWriteLockSQL();
     }
     if ($lockMode !== LockMode::OPTIMISTIC) {
         throw QueryException::invalidLockMode();
     }
     foreach ($this->selectedClasses as $selectedClass) {
         if (!$selectedClass['class']->isVersioned) {
             throw OptimisticLockException::lockFailed($selectedClass['class']->name);
         }
     }
     return $sql;
 }
 /**
  * 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;
 }