You are here

class SelectQuery_sqlsrv in Drupal driver for SQL Server and SQL Azure 7

Same name and namespace in other branches
  1. 7.3 sqlsrv/select.inc \SelectQuery_sqlsrv
  2. 7.2 sqlsrv/select.inc \SelectQuery_sqlsrv

Hierarchy

Expanded class hierarchy of SelectQuery_sqlsrv

File

sqlsrv/select.inc, line 3

View source
class SelectQuery_sqlsrv extends SelectQuery {

  /**
   * Override for SelectQuery::preExecute().
   *
   * Ensure that all the fields in ORDER BY and GROUP BY are part of the
   * main query.
   */
  public function preExecute(SelectQueryInterface $query = NULL) {

    // If no query object is passed in, use $this.
    if (!isset($query)) {
      $query = $this;
    }

    // Only execute this once.
    if ($this
      ->isPrepared()) {
      return TRUE;
    }

    // Execute standard pre-execution first.
    parent::preExecute($query);
    if ($this->distinct || $this->group) {

      // When the query is DISTINCT or contains GROUP BY fields, all the fields
      // in the GROUP BY and ORDER BY clauses must appear in the returned
      // columns.
      $columns = $this->order + array_flip($this->group);
      $counter = 0;
      foreach ($columns as $field => $dummy) {
        if (!isset($this->fields[$field]) && !isset($this->expressions[$field])) {
          $alias = '_field_' . $counter++;
          $this
            ->addExpression($field, $alias);
          $this->queryOptions['sqlsrv_drop_columns'][] = $alias;
        }
      }

      // More over, GROUP BY columns cannot use aliases, so expand them to
      // their full expressions.
      foreach ($this->group as $key => &$group_field) {

        // Expand an alias on a field.
        if (isset($this->fields[$group_field])) {
          $field = $this->fields[$group_field];
          $group_field = (isset($field['table']) ? $this->connection
            ->escapeTable($field['table']) . '.' : '') . $this->connection
            ->escapeField($field['field']);
        }
        else {
          if (isset($this->expressions[$group_field])) {
            $expression = $this->expressions[$group_field];
            $group_field = $expression['expression'];

            // If the expression has arguments, we now
            // have duplicate placeholders. Run as insecure.
            if (is_array($expression['arguments'])) {
              $this->queryOptions['insecure'] = TRUE;
            }
          }
        }
      }
    }
    return $this->prepared;
  }

  /**
   * Override for SelectQuery::compile().
   *
   * Detect when this query is prepared for use in a sub-query.
   */
  public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
    $this->inSubQuery = $queryPlaceholder != $this;
    return parent::compile($connection, $queryPlaceholder);
  }
  public function __toString() {

    // For convenience, we compile the query ourselves if the caller forgot
    // to do it. This allows constructs like "(string) $query" to work. When
    // the query will be executed, it will be recompiled using the proper
    // placeholder generator anyway.
    if (!$this
      ->compiled()) {
      $this
        ->compile($this->connection, $this);
    }

    // Create a sanitized comment string to prepend to the query.
    $comments = $this->connection
      ->makeComment($this->comments);

    // SELECT
    $query = $comments . 'SELECT ';
    if ($this->distinct) {
      $query .= 'DISTINCT ';
    }

    // FIELDS and EXPRESSIONS
    $fields = array();
    foreach ($this->tables as $alias => $table) {
      if (!empty($table['all_fields'])) {
        $fields[] = $this->connection
          ->escapeTable($alias) . '.*';
      }
    }
    foreach ($this->fields as $alias => $field) {

      // Always use the AS keyword for field aliases, as some
      // databases require it (e.g., PostgreSQL).
      $fields[] = (isset($field['table']) ? $this->connection
        ->escapeTable($field['table']) . '.' : '') . $this->connection
        ->escapeField($field['field']) . ' AS ' . $this->connection
        ->escapeField($field['alias']);
    }
    foreach ($this->expressions as $alias => $expression) {
      $fields[] = $expression['expression'] . ' AS ' . $expression['alias'];
    }
    $query .= implode(', ', $fields);

    // FROM - We presume all queries have a FROM, as any query that doesn't won't need the query builder anyway.
    $query .= "\nFROM ";
    foreach ($this->tables as $alias => $table) {
      $query .= "\n";
      if (isset($table['join type'])) {
        $query .= $table['join type'] . ' JOIN ';
      }

      // If the table is a subquery, compile it and integrate it into this query.
      if ($table['table'] instanceof SelectQueryInterface) {

        // Run preparation steps on this sub-query before converting to string.
        $subquery = $table['table'];
        $subquery
          ->preExecute();
        $table_string = '(' . (string) $subquery . ')';
      }
      else {
        $table_string = '{' . $this->connection
          ->escapeTable($table['table']) . '}';
      }

      // Don't use the AS keyword for table aliases, as some
      // databases don't support it (e.g., Oracle).
      $query .= $table_string . ' ' . $this->connection
        ->escapeTable($table['alias']);
      if (!empty($table['condition'])) {
        $query .= ' ON ' . $table['condition'];
      }
    }

    // WHERE
    if (count($this->where)) {

      // There is an implicit string cast on $this->condition.
      $query .= "\nWHERE ( " . $this->where . " )";
    }

    // GROUP BY
    if ($this->group) {
      $query .= "\nGROUP BY " . implode(', ', $this->group);
    }

    // HAVING
    if (count($this->having)) {

      // There is an implicit string cast on $this->having.
      $query .= "\nHAVING " . $this->having;
    }

    // ORDER BY
    // The ORDER BY clause is invalid in views, inline functions, derived
    // tables, subqueries, and common table expressions, unless TOP or FOR XML
    // is also specified.
    if ($this->order && (empty($this->inSubQuery) || !empty($this->range))) {
      $query .= "\nORDER BY ";
      $fields = array();
      foreach ($this->order as $field => $direction) {
        $fields[] = $field . ' ' . $direction;
      }
      $query .= implode(', ', $fields);
    }

    // RANGE
    if (!empty($this->range)) {
      $query = $this->connection
        ->addRangeToQuery($query, $this->range['start'], $this->range['length']);
    }

    // UNION is a little odd, as the select queries to combine are passed into
    // this query, but syntactically they all end up on the same level.
    if ($this->union) {
      foreach ($this->union as $union) {
        $query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
      }
    }
    return $query;
  }

  /**
   * Override of SelectQuery::orderRandom() for SQL Server.
   *
   * It seems that sorting by RAND() doesn't actually work, this is a less then
   * elegant workaround.
   *
   * @status tested
   */
  public function orderRandom() {
    $alias = $this
      ->addExpression('NEWID()', 'random_field');
    $this
      ->orderBy($alias);
    return $this;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Query::$comments protected property An array of comments that can be prepended to a query.
Query::$connection protected property The connection object on which to run this query.
Query::$connectionKey protected property The key of the connection object.
Query::$connectionTarget protected property The target of the connection object.
Query::$nextPlaceholder protected property The placeholder counter.
Query::$queryOptions protected property The query options to pass on to the connection object.
Query::$uniqueIdentifier protected property A unique identifier for this query object.
Query::comment public function Adds a comment to the query.
Query::getComments public function Returns a reference to the comments array for the query.
Query::nextPlaceholder public function Gets the next placeholder value for this query object. Overrides QueryPlaceholderInterface::nextPlaceholder
Query::uniqueIdentifier public function Returns a unique identifier for this object. Overrides QueryPlaceholderInterface::uniqueIdentifier
Query::__sleep public function Implements the magic __sleep function to disconnect from the database.
Query::__wakeup public function Implements the magic __wakeup function to reconnect to the database.
SelectQuery::$distinct protected property Whether or not this query should be DISTINCT
SelectQuery::$expressions protected property The expressions to SELECT as virtual fields.
SelectQuery::$fields protected property The fields to SELECT.
SelectQuery::$forUpdate protected property The FOR UPDATE status 1
SelectQuery::$group protected property The fields by which to group.
SelectQuery::$having protected property The conditional object for the HAVING clause.
SelectQuery::$order protected property The fields by which to order this query.
SelectQuery::$prepared protected property Indicates if preExecute() has already been called.
SelectQuery::$range protected property The range limiters for this query.
SelectQuery::$tables protected property The tables against which to JOIN.
SelectQuery::$union protected property An array whose elements specify a query to UNION, and the UNION type. The 'type' key may be '', 'ALL', or 'DISTINCT' to represent a 'UNION', 'UNION ALL', or 'UNION DISTINCT'…
SelectQuery::$where protected property The conditional object for the WHERE clause.
SelectQuery::addExpression public function Adds an expression to the list of "fields" to be SELECTed. Overrides SelectQueryInterface::addExpression
SelectQuery::addField public function Adds a field to the list to be SELECTed. Overrides SelectQueryInterface::addField
SelectQuery::addJoin public function Join against another table in the database. Overrides SelectQueryInterface::addJoin
SelectQuery::addMetaData public function Adds additional metadata to the query. Overrides QueryAlterableInterface::addMetaData
SelectQuery::addTag public function Adds a tag to a query. Overrides QueryAlterableInterface::addTag
SelectQuery::arguments public function Gets a complete list of all values to insert into the prepared statement. Overrides QueryConditionInterface::arguments
SelectQuery::compiled public function Check whether a condition has been previously compiled. Overrides QueryConditionInterface::compiled
SelectQuery::condition public function Helper function: builds the most common conditional clauses. Overrides QueryConditionInterface::condition
SelectQuery::conditions public function Gets a complete list of all conditions in this conditional clause. Overrides QueryConditionInterface::conditions
SelectQuery::countQuery public function Get the equivalent COUNT query of this query as a new query object. Overrides SelectQueryInterface::countQuery
SelectQuery::distinct public function Sets this query to be DISTINCT. Overrides SelectQueryInterface::distinct
SelectQuery::execute public function Runs the query against the database. Overrides Query::execute
SelectQuery::exists public function Sets a condition that the specified subquery returns values. Overrides QueryConditionInterface::exists
SelectQuery::extend public function Enhance this object by wrapping it in an extender object. Overrides QueryExtendableInterface::extend
SelectQuery::fields public function Add multiple fields from the same table to be SELECTed. Overrides SelectQueryInterface::fields
SelectQuery::forUpdate public function Add FOR UPDATE to the query. Overrides SelectQueryInterface::forUpdate 1
SelectQuery::getArguments public function Compiles and returns an associative array of the arguments for this prepared statement. Overrides SelectQueryInterface::getArguments
SelectQuery::getExpressions public function Returns a reference to the expressions array for this query. Overrides SelectQueryInterface::getExpressions
SelectQuery::getFields public function Returns a reference to the fields array for this query. Overrides SelectQueryInterface::getFields
SelectQuery::getGroupBy public function Returns a reference to the group-by array for this query. Overrides SelectQueryInterface::getGroupBy
SelectQuery::getMetaData public function Retrieves a given piece of metadata. Overrides QueryAlterableInterface::getMetaData
SelectQuery::getOrderBy public function Returns a reference to the order by array for this query. Overrides SelectQueryInterface::getOrderBy
SelectQuery::getTables public function Returns a reference to the tables array for this query. Overrides SelectQueryInterface::getTables
SelectQuery::getUnion public function Returns a reference to the union queries for this query. This include queries for UNION, UNION ALL, and UNION DISTINCT. Overrides SelectQueryInterface::getUnion
SelectQuery::groupBy public function Groups the result set by the specified field. Overrides SelectQueryInterface::groupBy
SelectQuery::hasAllTags public function Determines if a given query has all specified tags. Overrides QueryAlterableInterface::hasAllTags
SelectQuery::hasAnyTag public function Determines if a given query has any specified tag. Overrides QueryAlterableInterface::hasAnyTag
SelectQuery::hasTag public function Determines if a given query has a given tag. Overrides QueryAlterableInterface::hasTag
SelectQuery::having public function
SelectQuery::havingArguments public function
SelectQuery::havingCompile public function
SelectQuery::havingCondition public function Helper function to build most common HAVING conditional clauses. Overrides SelectQueryInterface::havingCondition
SelectQuery::havingConditions public function
SelectQuery::havingExists public function
SelectQuery::havingIsNotNull public function
SelectQuery::havingIsNull public function
SelectQuery::havingNotExists public function
SelectQuery::innerJoin public function Inner Join against another table in the database. Overrides SelectQueryInterface::innerJoin
SelectQuery::isNotNull public function Sets a condition that the specified field be NOT NULL. Overrides QueryConditionInterface::isNotNull
SelectQuery::isNull public function Sets a condition that the specified field be NULL. Overrides QueryConditionInterface::isNull
SelectQuery::isPrepared public function Indicates if preExecute() has already been called on that object. Overrides SelectQueryInterface::isPrepared
SelectQuery::join public function Default Join against another table in the database. Overrides SelectQueryInterface::join
SelectQuery::leftJoin public function Left Outer Join against another table in the database. Overrides SelectQueryInterface::leftJoin
SelectQuery::notExists public function Sets a condition that the specified subquery returns no values. Overrides QueryConditionInterface::notExists
SelectQuery::orderBy public function Orders the result set by a given field. Overrides SelectQueryInterface::orderBy 1
SelectQuery::range public function Restricts a query to a given range in the result set. Overrides SelectQueryInterface::range
SelectQuery::rightJoin public function Right Outer Join against another table in the database. Overrides SelectQueryInterface::rightJoin
SelectQuery::union public function Add another Select query to UNION to this one. Overrides SelectQueryInterface::union
SelectQuery::where public function Adds an arbitrary WHERE clause to the query. Overrides QueryConditionInterface::where
SelectQuery::__clone public function Implements the magic __clone function. Overrides Query::__clone
SelectQuery::__construct public function Constructs a Query object. Overrides Query::__construct
SelectQuery_sqlsrv::compile public function Override for SelectQuery::compile(). Overrides SelectQuery::compile
SelectQuery_sqlsrv::orderRandom public function Override of SelectQuery::orderRandom() for SQL Server. Overrides SelectQuery::orderRandom
SelectQuery_sqlsrv::preExecute public function Override for SelectQuery::preExecute(). Overrides SelectQuery::preExecute
SelectQuery_sqlsrv::__toString public function Implements PHP magic __toString method to convert the query to a string. Overrides SelectQuery::__toString