cms/drupal/includes/database/select.inc
changeset 541 e756a8c72c3d
equal deleted inserted replaced
540:07239de796bb 541:e756a8c72c3d
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * @addtogroup database
       
     5  * @{
       
     6  */
       
     7 
       
     8 require_once dirname(__FILE__) . '/query.inc';
       
     9 
       
    10 /**
       
    11  * Interface for extendable query objects.
       
    12  *
       
    13  * "Extenders" follow the "Decorator" OOP design pattern.  That is, they wrap
       
    14  * and "decorate" another object.  In our case, they implement the same interface
       
    15  * as select queries and wrap a select query, to which they delegate almost all
       
    16  * operations.  Subclasses of this class may implement additional methods or
       
    17  * override existing methods as appropriate.  Extenders may also wrap other
       
    18  * extender objects, allowing for arbitrarily complex "enhanced" queries.
       
    19  */
       
    20 interface QueryExtendableInterface {
       
    21 
       
    22   /**
       
    23    * Enhance this object by wrapping it in an extender object.
       
    24    *
       
    25    * @param $extender_name
       
    26    *   The base name of the extending class.  The base name will be checked
       
    27    *   against the current database connection to allow driver-specific subclasses
       
    28    *   as well, using the same logic as the query objects themselves.  For example,
       
    29    *   PagerDefault_mysql is the MySQL-specific override for PagerDefault.
       
    30    * @return QueryExtendableInterface
       
    31    *   The extender object, which now contains a reference to this object.
       
    32    */
       
    33   public function extend($extender_name);
       
    34 }
       
    35 
       
    36 /**
       
    37  * Interface definition for a Select Query object.
       
    38  */
       
    39 interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableInterface, QueryExtendableInterface, QueryPlaceholderInterface {
       
    40 
       
    41   /* Alter accessors to expose the query data to alter hooks. */
       
    42 
       
    43   /**
       
    44    * Returns a reference to the fields array for this query.
       
    45    *
       
    46    * Because this method returns by reference, alter hooks may edit the fields
       
    47    * array directly to make their changes. If just adding fields, however, the
       
    48    * use of addField() is preferred.
       
    49    *
       
    50    * Note that this method must be called by reference as well:
       
    51    *
       
    52    * @code
       
    53    * $fields =& $query->getFields();
       
    54    * @endcode
       
    55    *
       
    56    * @return
       
    57    *   A reference to the fields array structure.
       
    58    */
       
    59   public function &getFields();
       
    60 
       
    61   /**
       
    62    * Returns a reference to the expressions array for this query.
       
    63    *
       
    64    * Because this method returns by reference, alter hooks may edit the expressions
       
    65    * array directly to make their changes. If just adding expressions, however, the
       
    66    * use of addExpression() is preferred.
       
    67    *
       
    68    * Note that this method must be called by reference as well:
       
    69    *
       
    70    * @code
       
    71    * $fields =& $query->getExpressions();
       
    72    * @endcode
       
    73    *
       
    74    * @return
       
    75    *   A reference to the expression array structure.
       
    76    */
       
    77   public function &getExpressions();
       
    78 
       
    79   /**
       
    80    * Returns a reference to the order by array for this query.
       
    81    *
       
    82    * Because this method returns by reference, alter hooks may edit the order-by
       
    83    * array directly to make their changes. If just adding additional ordering
       
    84    * fields, however, the use of orderBy() is preferred.
       
    85    *
       
    86    * Note that this method must be called by reference as well:
       
    87    *
       
    88    * @code
       
    89    * $fields =& $query->getOrderBy();
       
    90    * @endcode
       
    91    *
       
    92    * @return
       
    93    *   A reference to the expression array structure.
       
    94    */
       
    95   public function &getOrderBy();
       
    96 
       
    97   /**
       
    98    * Returns a reference to the group-by array for this query.
       
    99    *
       
   100    * Because this method returns by reference, alter hooks may edit the group-by
       
   101    * array directly to make their changes. If just adding additional grouping
       
   102    * fields, however, the use of groupBy() is preferred.
       
   103    *
       
   104    * Note that this method must be called by reference as well:
       
   105    *
       
   106    * @code
       
   107    * $fields =& $query->getGroupBy();
       
   108    * @endcode
       
   109    *
       
   110    * @return
       
   111    *   A reference to the group-by array structure.
       
   112    */
       
   113   public function &getGroupBy();
       
   114 
       
   115   /**
       
   116    * Returns a reference to the tables array for this query.
       
   117    *
       
   118    * Because this method returns by reference, alter hooks may edit the tables
       
   119    * array directly to make their changes. If just adding tables, however, the
       
   120    * use of the join() methods is preferred.
       
   121    *
       
   122    * Note that this method must be called by reference as well:
       
   123    *
       
   124    * @code
       
   125    * $fields =& $query->getTables();
       
   126    * @endcode
       
   127    *
       
   128    * @return
       
   129    *   A reference to the tables array structure.
       
   130    */
       
   131   public function &getTables();
       
   132 
       
   133   /**
       
   134    * Returns a reference to the union queries for this query. This include
       
   135    * queries for UNION, UNION ALL, and UNION DISTINCT.
       
   136    *
       
   137    * Because this method returns by reference, alter hooks may edit the tables
       
   138    * array directly to make their changes. If just adding union queries,
       
   139    * however, the use of the union() method is preferred.
       
   140    *
       
   141    * Note that this method must be called by reference as well:
       
   142    *
       
   143    * @code
       
   144    * $fields =& $query->getUnion();
       
   145    * @endcode
       
   146    *
       
   147    * @return
       
   148    *   A reference to the union query array structure.
       
   149    */
       
   150   public function &getUnion();
       
   151 
       
   152   /**
       
   153    * Compiles and returns an associative array of the arguments for this prepared statement.
       
   154    *
       
   155    * @param $queryPlaceholder
       
   156    *   When collecting the arguments of a subquery, the main placeholder
       
   157    *   object should be passed as this parameter.
       
   158    *
       
   159    * @return
       
   160    *   An associative array of all placeholder arguments for this query.
       
   161    */
       
   162   public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL);
       
   163 
       
   164   /* Query building operations */
       
   165 
       
   166   /**
       
   167    * Sets this query to be DISTINCT.
       
   168    *
       
   169    * @param $distinct
       
   170    *   TRUE to flag this query DISTINCT, FALSE to disable it.
       
   171    * @return SelectQueryInterface
       
   172    *   The called object.
       
   173    */
       
   174   public function distinct($distinct = TRUE);
       
   175 
       
   176   /**
       
   177    * Adds a field to the list to be SELECTed.
       
   178    *
       
   179    * @param $table_alias
       
   180    *   The name of the table from which the field comes, as an alias. Generally
       
   181    *   you will want to use the return value of join() here to ensure that it is
       
   182    *   valid.
       
   183    * @param $field
       
   184    *   The name of the field.
       
   185    * @param $alias
       
   186    *   The alias for this field. If not specified, one will be generated
       
   187    *   automatically based on the $table_alias and $field. The alias will be
       
   188    *   checked for uniqueness, so the requested alias may not be the alias
       
   189    *   that is assigned in all cases.
       
   190    * @return
       
   191    *   The unique alias that was assigned for this field.
       
   192    */
       
   193   public function addField($table_alias, $field, $alias = NULL);
       
   194 
       
   195   /**
       
   196    * Add multiple fields from the same table to be SELECTed.
       
   197    *
       
   198    * This method does not return the aliases set for the passed fields. In the
       
   199    * majority of cases that is not a problem, as the alias will be the field
       
   200    * name. However, if you do need to know the alias you can call getFields()
       
   201    * and examine the result to determine what alias was created. Alternatively,
       
   202    * simply use addField() for the few fields you care about and this method for
       
   203    * the rest.
       
   204    *
       
   205    * @param $table_alias
       
   206    *   The name of the table from which the field comes, as an alias. Generally
       
   207    *   you will want to use the return value of join() here to ensure that it is
       
   208    *   valid.
       
   209    * @param $fields
       
   210    *   An indexed array of fields present in the specified table that should be
       
   211    *   included in this query. If not specified, $table_alias.* will be generated
       
   212    *   without any aliases.
       
   213    * @return SelectQueryInterface
       
   214    *   The called object.
       
   215    */
       
   216   public function fields($table_alias, array $fields = array());
       
   217 
       
   218   /**
       
   219    * Adds an expression to the list of "fields" to be SELECTed.
       
   220    *
       
   221    * An expression can be any arbitrary string that is valid SQL. That includes
       
   222    * various functions, which may in some cases be database-dependent. This
       
   223    * method makes no effort to correct for database-specific functions.
       
   224    *
       
   225    * @param $expression
       
   226    *   The expression string. May contain placeholders.
       
   227    * @param $alias
       
   228    *   The alias for this expression. If not specified, one will be generated
       
   229    *   automatically in the form "expression_#". The alias will be checked for
       
   230    *   uniqueness, so the requested alias may not be the alias that is assigned
       
   231    *   in all cases.
       
   232    * @param $arguments
       
   233    *   Any placeholder arguments needed for this expression.
       
   234    * @return
       
   235    *   The unique alias that was assigned for this expression.
       
   236    */
       
   237   public function addExpression($expression, $alias = NULL, $arguments = array());
       
   238 
       
   239   /**
       
   240    * Default Join against another table in the database.
       
   241    *
       
   242    * This method is a convenience method for innerJoin().
       
   243    *
       
   244    * @param $table
       
   245    *   The table against which to join.
       
   246    * @param $alias
       
   247    *   The alias for the table. In most cases this should be the first letter
       
   248    *   of the table, or the first letter of each "word" in the table.
       
   249    * @param $condition
       
   250    *   The condition on which to join this table. If the join requires values,
       
   251    *   this clause should use a named placeholder and the value or values to
       
   252    *   insert should be passed in the 4th parameter. For the first table joined
       
   253    *   on a query, this value is ignored as the first table is taken as the base
       
   254    *   table. The token %alias can be used in this string to be replaced with
       
   255    *   the actual alias. This is useful when $alias is modified by the database
       
   256    *   system, for example, when joining the same table more than once.
       
   257    * @param $arguments
       
   258    *   An array of arguments to replace into the $condition of this join.
       
   259    * @return
       
   260    *   The unique alias that was assigned for this table.
       
   261    */
       
   262   public function join($table, $alias = NULL, $condition = NULL, $arguments = array());
       
   263 
       
   264   /**
       
   265    * Inner Join against another table in the database.
       
   266    *
       
   267    * @param $table
       
   268    *   The table against which to join.
       
   269    * @param $alias
       
   270    *   The alias for the table. In most cases this should be the first letter
       
   271    *   of the table, or the first letter of each "word" in the table.
       
   272    * @param $condition
       
   273    *   The condition on which to join this table. If the join requires values,
       
   274    *   this clause should use a named placeholder and the value or values to
       
   275    *   insert should be passed in the 4th parameter. For the first table joined
       
   276    *   on a query, this value is ignored as the first table is taken as the base
       
   277    *   table. The token %alias can be used in this string to be replaced with
       
   278    *   the actual alias. This is useful when $alias is modified by the database
       
   279    *   system, for example, when joining the same table more than once.
       
   280    * @param $arguments
       
   281    *   An array of arguments to replace into the $condition of this join.
       
   282    * @return
       
   283    *   The unique alias that was assigned for this table.
       
   284    */
       
   285   public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
       
   286 
       
   287   /**
       
   288    * Left Outer Join against another table in the database.
       
   289    *
       
   290    * @param $table
       
   291    *   The table against which to join.
       
   292    * @param $alias
       
   293    *   The alias for the table. In most cases this should be the first letter
       
   294    *   of the table, or the first letter of each "word" in the table.
       
   295    * @param $condition
       
   296    *   The condition on which to join this table. If the join requires values,
       
   297    *   this clause should use a named placeholder and the value or values to
       
   298    *   insert should be passed in the 4th parameter. For the first table joined
       
   299    *   on a query, this value is ignored as the first table is taken as the base
       
   300    *   table. The token %alias can be used in this string to be replaced with
       
   301    *   the actual alias. This is useful when $alias is modified by the database
       
   302    *   system, for example, when joining the same table more than once.
       
   303    * @param $arguments
       
   304    *   An array of arguments to replace into the $condition of this join.
       
   305    * @return
       
   306    *   The unique alias that was assigned for this table.
       
   307    */
       
   308   public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
       
   309 
       
   310   /**
       
   311    * Right Outer Join against another table in the database.
       
   312    *
       
   313    * @param $table
       
   314    *   The table against which to join.
       
   315    * @param $alias
       
   316    *   The alias for the table. In most cases this should be the first letter
       
   317    *   of the table, or the first letter of each "word" in the table.
       
   318    * @param $condition
       
   319    *   The condition on which to join this table. If the join requires values,
       
   320    *   this clause should use a named placeholder and the value or values to
       
   321    *   insert should be passed in the 4th parameter. For the first table joined
       
   322    *   on a query, this value is ignored as the first table is taken as the base
       
   323    *   table. The token %alias can be used in this string to be replaced with
       
   324    *   the actual alias. This is useful when $alias is modified by the database
       
   325    *   system, for example, when joining the same table more than once.
       
   326    * @param $arguments
       
   327    *   An array of arguments to replace into the $condition of this join.
       
   328    * @return
       
   329    *   The unique alias that was assigned for this table.
       
   330    */
       
   331   public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array());
       
   332 
       
   333   /**
       
   334    * Join against another table in the database.
       
   335    *
       
   336    * This method does the "hard" work of queuing up a table to be joined against.
       
   337    * In some cases, that may include dipping into the Schema API to find the necessary
       
   338    * fields on which to join.
       
   339    *
       
   340    * @param $type
       
   341    *   The type of join. Typically one one of INNER, LEFT OUTER, and RIGHT OUTER.
       
   342    * @param $table
       
   343    *   The table against which to join. May be a string or another SelectQuery
       
   344    *   object. If a query object is passed, it will be used as a subselect.
       
   345    * @param $alias
       
   346    *   The alias for the table. In most cases this should be the first letter
       
   347    *   of the table, or the first letter of each "word" in the table. If omitted,
       
   348    *   one will be dynamically generated.
       
   349    * @param $condition
       
   350    *   The condition on which to join this table. If the join requires values,
       
   351    *   this clause should use a named placeholder and the value or values to
       
   352    *   insert should be passed in the 4th parameter. For the first table joined
       
   353    *   on a query, this value is ignored as the first table is taken as the base
       
   354    *   table. The token %alias can be used in this string to be replaced with
       
   355    *   the actual alias. This is useful when $alias is modified by the database
       
   356    *   system, for example, when joining the same table more than once.
       
   357    * @param $arguments
       
   358    *   An array of arguments to replace into the $condition of this join.
       
   359    * @return
       
   360    *   The unique alias that was assigned for this table.
       
   361    */
       
   362   public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array());
       
   363 
       
   364   /**
       
   365    * Orders the result set by a given field.
       
   366    *
       
   367    * If called multiple times, the query will order by each specified field in the
       
   368    * order this method is called.
       
   369    *
       
   370    * If the query uses DISTINCT or GROUP BY conditions, fields or expressions
       
   371    * that are used for the order must be selected to be compatible with some
       
   372    * databases like PostgreSQL. The PostgreSQL driver can handle simple cases
       
   373    * automatically but it is suggested to explicitly specify them. Additionally,
       
   374    * when ordering on an alias, the alias must be added before orderBy() is
       
   375    * called.
       
   376    *
       
   377    * @param $field
       
   378    *   The field on which to order.
       
   379    * @param $direction
       
   380    *   The direction to sort. Legal values are "ASC" and "DESC". Any other value
       
   381    *   will be converted to "ASC".
       
   382    * @return SelectQueryInterface
       
   383    *   The called object.
       
   384    */
       
   385   public function orderBy($field, $direction = 'ASC');
       
   386 
       
   387   /**
       
   388    * Orders the result set by a random value.
       
   389    *
       
   390    * This may be stacked with other orderBy() calls. If so, the query will order
       
   391    * by each specified field, including this one, in the order called. Although
       
   392    * this method may be called multiple times on the same query, doing so
       
   393    * is not particularly useful.
       
   394    *
       
   395    * Note: The method used by most drivers may not scale to very large result
       
   396    * sets. If you need to work with extremely large data sets, you may create
       
   397    * your own database driver by subclassing off of an existing driver and
       
   398    * implementing your own randomization mechanism. See
       
   399    *
       
   400    * http://jan.kneschke.de/projects/mysql/order-by-rand/
       
   401    *
       
   402    * for an example of such an alternate sorting mechanism.
       
   403    *
       
   404    * @return SelectQueryInterface
       
   405    *   The called object
       
   406    */
       
   407   public function orderRandom();
       
   408 
       
   409   /**
       
   410    * Restricts a query to a given range in the result set.
       
   411    *
       
   412    * If this method is called with no parameters, will remove any range
       
   413    * directives that have been set.
       
   414    *
       
   415    * @param $start
       
   416    *   The first record from the result set to return. If NULL, removes any
       
   417    *   range directives that are set.
       
   418    * @param $length
       
   419    *   The number of records to return from the result set.
       
   420    * @return SelectQueryInterface
       
   421    *   The called object.
       
   422    */
       
   423   public function range($start = NULL, $length = NULL);
       
   424 
       
   425   /**
       
   426    * Add another Select query to UNION to this one.
       
   427    *
       
   428    * Union queries consist of two or more queries whose
       
   429    * results are effectively concatenated together. Queries
       
   430    * will be UNIONed in the order they are specified, with
       
   431    * this object's query coming first. Duplicate columns will
       
   432    * be discarded. All forms of UNION are supported, using
       
   433    * the second '$type' argument.
       
   434    *
       
   435    * Note: All queries UNIONed together must have the same
       
   436    * field structure, in the same order. It is up to the
       
   437    * caller to ensure that they match properly. If they do
       
   438    * not, an SQL syntax error will result.
       
   439    *
       
   440    * @param $query
       
   441    *   The query to UNION to this query.
       
   442    * @param $type
       
   443    *   The type of UNION to add to the query. Defaults to plain
       
   444    *   UNION.
       
   445    * @return SelectQueryInterface
       
   446    *   The called object.
       
   447    */
       
   448   public function union(SelectQueryInterface $query, $type = '');
       
   449 
       
   450   /**
       
   451    * Groups the result set by the specified field.
       
   452    *
       
   453    * @param $field
       
   454    *   The field on which to group. This should be the field as aliased.
       
   455    * @return SelectQueryInterface
       
   456    *   The called object.
       
   457    */
       
   458   public function groupBy($field);
       
   459 
       
   460   /**
       
   461    * Get the equivalent COUNT query of this query as a new query object.
       
   462    *
       
   463    * @return SelectQueryInterface
       
   464    *   A new SelectQuery object with no fields or expressions besides COUNT(*).
       
   465    */
       
   466   public function countQuery();
       
   467 
       
   468   /**
       
   469    * Indicates if preExecute() has already been called on that object.
       
   470    *
       
   471    * @return
       
   472    *   TRUE is this query has already been prepared, FALSE otherwise.
       
   473    */
       
   474   public function isPrepared();
       
   475 
       
   476   /**
       
   477    * Generic preparation and validation for a SELECT query.
       
   478    *
       
   479    * @return
       
   480    *   TRUE if the validation was successful, FALSE if not.
       
   481    */
       
   482   public function preExecute(SelectQueryInterface $query = NULL);
       
   483 
       
   484   /**
       
   485    * Helper function to build most common HAVING conditional clauses.
       
   486    *
       
   487    * This method can take a variable number of parameters. If called with two
       
   488    * parameters, they are taken as $field and $value with $operator having a value
       
   489    * of IN if $value is an array and = otherwise.
       
   490    *
       
   491    * @param $field
       
   492    *   The name of the field to check. If you would like to add a more complex
       
   493    *   condition involving operators or functions, use having().
       
   494    * @param $value
       
   495    *   The value to test the field against. In most cases, this is a scalar. For more
       
   496    *   complex options, it is an array. The meaning of each element in the array is
       
   497    *   dependent on the $operator.
       
   498    * @param $operator
       
   499    *   The comparison operator, such as =, <, or >=. It also accepts more complex
       
   500    *   options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is an array
       
   501    *   = otherwise.
       
   502    * @return QueryConditionInterface
       
   503    *   The called object.
       
   504    */
       
   505   public function havingCondition($field, $value = NULL, $operator = NULL);
       
   506 
       
   507   /**
       
   508    * Clone magic method.
       
   509    *
       
   510    * Select queries have dependent objects that must be deep-cloned.  The
       
   511    * connection object itself, however, should not be cloned as that would
       
   512    * duplicate the connection itself.
       
   513    */
       
   514   public function __clone();
       
   515 
       
   516   /**
       
   517    * Add FOR UPDATE to the query.
       
   518    *
       
   519    * FOR UPDATE prevents the rows retrieved by the SELECT statement from being
       
   520    * modified or deleted by other transactions until the current transaction
       
   521    * ends. Other transactions that attempt UPDATE, DELETE, or SELECT FOR UPDATE
       
   522    * of these rows will be blocked until the current transaction ends.
       
   523    *
       
   524    * @param $set
       
   525    *   IF TRUE, FOR UPDATE will be added to the query, if FALSE then it won't.
       
   526    *
       
   527    * @return QueryConditionInterface
       
   528    *   The called object.
       
   529    */
       
   530   public function forUpdate($set = TRUE);
       
   531 }
       
   532 
       
   533 /**
       
   534  * The base extender class for Select queries.
       
   535  */
       
   536 class SelectQueryExtender implements SelectQueryInterface {
       
   537 
       
   538   /**
       
   539    * The SelectQuery object we are extending/decorating.
       
   540    *
       
   541    * @var SelectQueryInterface
       
   542    */
       
   543   protected $query;
       
   544 
       
   545   /**
       
   546    * The connection object on which to run this query.
       
   547    *
       
   548    * @var DatabaseConnection
       
   549    */
       
   550   protected $connection;
       
   551 
       
   552   /**
       
   553    * A unique identifier for this query object.
       
   554    */
       
   555   protected $uniqueIdentifier;
       
   556 
       
   557   /**
       
   558    * The placeholder counter.
       
   559    */
       
   560   protected $placeholder = 0;
       
   561 
       
   562   public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
       
   563     $this->uniqueIdentifier = uniqid('', TRUE);
       
   564     $this->query = $query;
       
   565     $this->connection = $connection;
       
   566   }
       
   567 
       
   568   /**
       
   569    * Implements QueryPlaceholderInterface::uniqueIdentifier().
       
   570    */
       
   571   public function uniqueIdentifier() {
       
   572     return $this->uniqueIdentifier;
       
   573   }
       
   574 
       
   575   /**
       
   576    * Implements QueryPlaceholderInterface::nextPlaceholder().
       
   577    */
       
   578   public function nextPlaceholder() {
       
   579     return $this->placeholder++;
       
   580   }
       
   581 
       
   582   /* Implementations of QueryAlterableInterface. */
       
   583 
       
   584   public function addTag($tag) {
       
   585     $this->query->addTag($tag);
       
   586     return $this;
       
   587   }
       
   588 
       
   589   public function hasTag($tag) {
       
   590     return $this->query->hasTag($tag);
       
   591   }
       
   592 
       
   593   public function hasAllTags() {
       
   594     $args = func_get_args();
       
   595     return call_user_func_array(array($this->query, 'hasAllTags'), $args);
       
   596   }
       
   597 
       
   598   public function hasAnyTag() {
       
   599     $args = func_get_args();
       
   600     return call_user_func_array(array($this->query, 'hasAnyTag'), $args);
       
   601   }
       
   602 
       
   603   public function addMetaData($key, $object) {
       
   604     $this->query->addMetaData($key, $object);
       
   605     return $this;
       
   606   }
       
   607 
       
   608   public function getMetaData($key) {
       
   609     return $this->query->getMetaData($key);
       
   610   }
       
   611 
       
   612   /* Implementations of QueryConditionInterface for the WHERE clause. */
       
   613 
       
   614   public function condition($field, $value = NULL, $operator = NULL) {
       
   615     $this->query->condition($field, $value, $operator);
       
   616     return $this;
       
   617   }
       
   618 
       
   619   public function &conditions() {
       
   620     return $this->query->conditions();
       
   621   }
       
   622 
       
   623   public function arguments() {
       
   624     return $this->query->arguments();
       
   625   }
       
   626 
       
   627   public function where($snippet, $args = array()) {
       
   628     $this->query->where($snippet, $args);
       
   629     return $this;
       
   630   }
       
   631 
       
   632   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
       
   633     return $this->query->compile($connection, $queryPlaceholder);
       
   634   }
       
   635 
       
   636   public function compiled() {
       
   637     return $this->query->compiled();
       
   638   }
       
   639 
       
   640   /* Implementations of QueryConditionInterface for the HAVING clause. */
       
   641 
       
   642   public function havingCondition($field, $value = NULL, $operator = '=') {
       
   643     $this->query->havingCondition($field, $value, $operator);
       
   644     return $this;
       
   645   }
       
   646 
       
   647   public function &havingConditions() {
       
   648     return $this->query->havingConditions();
       
   649   }
       
   650 
       
   651   public function havingArguments() {
       
   652     return $this->query->havingArguments();
       
   653   }
       
   654 
       
   655   public function having($snippet, $args = array()) {
       
   656     $this->query->having($snippet, $args);
       
   657     return $this;
       
   658   }
       
   659 
       
   660   public function havingCompile(DatabaseConnection $connection) {
       
   661     return $this->query->havingCompile($connection);
       
   662   }
       
   663 
       
   664   /* Implementations of QueryExtendableInterface. */
       
   665 
       
   666   public function extend($extender_name) {
       
   667     // The extender can be anywhere so this needs to go to the registry, which
       
   668     // is surely loaded by now.
       
   669     $class = $this->connection->getDriverClass($extender_name, array(), TRUE);
       
   670     return new $class($this, $this->connection);
       
   671   }
       
   672 
       
   673   /* Alter accessors to expose the query data to alter hooks. */
       
   674 
       
   675   public function &getFields() {
       
   676     return $this->query->getFields();
       
   677   }
       
   678 
       
   679   public function &getExpressions() {
       
   680     return $this->query->getExpressions();
       
   681   }
       
   682 
       
   683   public function &getOrderBy() {
       
   684     return $this->query->getOrderBy();
       
   685   }
       
   686 
       
   687   public function &getGroupBy() {
       
   688     return $this->query->getGroupBy();
       
   689   }
       
   690 
       
   691   public function &getTables() {
       
   692     return $this->query->getTables();
       
   693   }
       
   694 
       
   695   public function &getUnion() {
       
   696     return $this->query->getUnion();
       
   697   }
       
   698 
       
   699   public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL) {
       
   700     return $this->query->getArguments($queryPlaceholder);
       
   701   }
       
   702 
       
   703   public function isPrepared() {
       
   704     return $this->query->isPrepared();
       
   705   }
       
   706 
       
   707   public function preExecute(SelectQueryInterface $query = NULL) {
       
   708     // If no query object is passed in, use $this.
       
   709     if (!isset($query)) {
       
   710       $query = $this;
       
   711     }
       
   712 
       
   713     return $this->query->preExecute($query);
       
   714   }
       
   715 
       
   716   public function execute() {
       
   717     // By calling preExecute() here, we force it to preprocess the extender
       
   718     // object rather than just the base query object.  That means
       
   719     // hook_query_alter() gets access to the extended object.
       
   720     if (!$this->preExecute($this)) {
       
   721       return NULL;
       
   722     }
       
   723 
       
   724     return $this->query->execute();
       
   725   }
       
   726 
       
   727   public function distinct($distinct = TRUE) {
       
   728     $this->query->distinct($distinct);
       
   729     return $this;
       
   730   }
       
   731 
       
   732   public function addField($table_alias, $field, $alias = NULL) {
       
   733     return $this->query->addField($table_alias, $field, $alias);
       
   734   }
       
   735 
       
   736   public function fields($table_alias, array $fields = array()) {
       
   737     $this->query->fields($table_alias, $fields);
       
   738     return $this;
       
   739   }
       
   740 
       
   741   public function addExpression($expression, $alias = NULL, $arguments = array()) {
       
   742     return $this->query->addExpression($expression, $alias, $arguments);
       
   743   }
       
   744 
       
   745   public function join($table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
   746     return $this->query->join($table, $alias, $condition, $arguments);
       
   747   }
       
   748 
       
   749   public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
   750     return $this->query->innerJoin($table, $alias, $condition, $arguments);
       
   751   }
       
   752 
       
   753   public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
   754     return $this->query->leftJoin($table, $alias, $condition, $arguments);
       
   755   }
       
   756 
       
   757   public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
   758     return $this->query->rightJoin($table, $alias, $condition, $arguments);
       
   759   }
       
   760 
       
   761   public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
   762     return $this->query->addJoin($type, $table, $alias, $condition, $arguments);
       
   763   }
       
   764 
       
   765   public function orderBy($field, $direction = 'ASC') {
       
   766     $this->query->orderBy($field, $direction);
       
   767     return $this;
       
   768   }
       
   769 
       
   770   public function orderRandom() {
       
   771     $this->query->orderRandom();
       
   772     return $this;
       
   773   }
       
   774 
       
   775   public function range($start = NULL, $length = NULL) {
       
   776     $this->query->range($start, $length);
       
   777     return $this;
       
   778   }
       
   779 
       
   780   public function union(SelectQueryInterface $query, $type = '') {
       
   781     $this->query->union($query, $type);
       
   782     return $this;
       
   783   }
       
   784 
       
   785   public function groupBy($field) {
       
   786     $this->query->groupBy($field);
       
   787     return $this;
       
   788   }
       
   789 
       
   790   public function forUpdate($set = TRUE) {
       
   791     $this->query->forUpdate($set);
       
   792     return $this;
       
   793   }
       
   794 
       
   795   public function countQuery() {
       
   796     return $this->query->countQuery();
       
   797   }
       
   798 
       
   799   function isNull($field) {
       
   800     $this->query->isNull($field);
       
   801     return $this;
       
   802   }
       
   803 
       
   804   function isNotNull($field) {
       
   805     $this->query->isNotNull($field);
       
   806     return $this;
       
   807   }
       
   808 
       
   809   public function exists(SelectQueryInterface $select) {
       
   810     $this->query->exists($select);
       
   811     return $this;
       
   812   }
       
   813 
       
   814   public function notExists(SelectQueryInterface $select) {
       
   815     $this->query->notExists($select);
       
   816     return $this;
       
   817   }
       
   818 
       
   819   public function __toString() {
       
   820     return (string) $this->query;
       
   821   }
       
   822 
       
   823   public function __clone() {
       
   824     $this->uniqueIdentifier = uniqid('', TRUE);
       
   825 
       
   826     // We need to deep-clone the query we're wrapping, which in turn may
       
   827     // deep-clone other objects.  Exciting!
       
   828     $this->query = clone($this->query);
       
   829   }
       
   830 
       
   831   /**
       
   832    * Magic override for undefined methods.
       
   833    *
       
   834    * If one extender extends another extender, then methods in the inner extender
       
   835    * will not be exposed on the outer extender.  That's because we cannot know
       
   836    * in advance what those methods will be, so we cannot provide wrapping
       
   837    * implementations as we do above.  Instead, we use this slower catch-all method
       
   838    * to handle any additional methods.
       
   839    */
       
   840   public function __call($method, $args) {
       
   841     $return = call_user_func_array(array($this->query, $method), $args);
       
   842 
       
   843     // Some methods will return the called object as part of a fluent interface.
       
   844     // Others will return some useful value.  If it's a value, then the caller
       
   845     // probably wants that value.  If it's the called object, then we instead
       
   846     // return this object.  That way we don't "lose" an extender layer when
       
   847     // chaining methods together.
       
   848     if ($return instanceof SelectQueryInterface) {
       
   849       return $this;
       
   850     }
       
   851     else {
       
   852       return $return;
       
   853     }
       
   854   }
       
   855 }
       
   856 
       
   857 /**
       
   858  * Query builder for SELECT statements.
       
   859  */
       
   860 class SelectQuery extends Query implements SelectQueryInterface {
       
   861 
       
   862   /**
       
   863    * The fields to SELECT.
       
   864    *
       
   865    * @var array
       
   866    */
       
   867   protected $fields = array();
       
   868 
       
   869   /**
       
   870    * The expressions to SELECT as virtual fields.
       
   871    *
       
   872    * @var array
       
   873    */
       
   874   protected $expressions = array();
       
   875 
       
   876   /**
       
   877    * The tables against which to JOIN.
       
   878    *
       
   879    * This property is a nested array. Each entry is an array representing
       
   880    * a single table against which to join. The structure of each entry is:
       
   881    *
       
   882    * array(
       
   883    *   'type' => $join_type (one of INNER, LEFT OUTER, RIGHT OUTER),
       
   884    *   'table' => $table,
       
   885    *   'alias' => $alias_of_the_table,
       
   886    *   'condition' => $condition_clause_on_which_to_join,
       
   887    *   'arguments' => $array_of_arguments_for_placeholders_in_the condition.
       
   888    *   'all_fields' => TRUE to SELECT $alias.*, FALSE or NULL otherwise.
       
   889    * )
       
   890    *
       
   891    * If $table is a string, it is taken as the name of a table. If it is
       
   892    * a SelectQuery object, it is taken as a subquery.
       
   893    *
       
   894    * @var array
       
   895    */
       
   896   protected $tables = array();
       
   897 
       
   898   /**
       
   899    * The fields by which to order this query.
       
   900    *
       
   901    * This is an associative array. The keys are the fields to order, and the value
       
   902    * is the direction to order, either ASC or DESC.
       
   903    *
       
   904    * @var array
       
   905    */
       
   906   protected $order = array();
       
   907 
       
   908   /**
       
   909    * The fields by which to group.
       
   910    *
       
   911    * @var array
       
   912    */
       
   913   protected $group = array();
       
   914 
       
   915   /**
       
   916    * The conditional object for the WHERE clause.
       
   917    *
       
   918    * @var DatabaseCondition
       
   919    */
       
   920   protected $where;
       
   921 
       
   922   /**
       
   923    * The conditional object for the HAVING clause.
       
   924    *
       
   925    * @var DatabaseCondition
       
   926    */
       
   927   protected $having;
       
   928 
       
   929   /**
       
   930    * Whether or not this query should be DISTINCT
       
   931    *
       
   932    * @var boolean
       
   933    */
       
   934   protected $distinct = FALSE;
       
   935 
       
   936   /**
       
   937    * The range limiters for this query.
       
   938    *
       
   939    * @var array
       
   940    */
       
   941   protected $range;
       
   942 
       
   943   /**
       
   944    * An array whose elements specify a query to UNION, and the UNION type. The
       
   945    * 'type' key may be '', 'ALL', or 'DISTINCT' to represent a 'UNION',
       
   946    * 'UNION ALL', or 'UNION DISTINCT' statement, respectively.
       
   947    *
       
   948    * All entries in this array will be applied from front to back, with the
       
   949    * first query to union on the right of the original query, the second union
       
   950    * to the right of the first, etc.
       
   951    *
       
   952    * @var array
       
   953    */
       
   954   protected $union = array();
       
   955 
       
   956   /**
       
   957    * Indicates if preExecute() has already been called.
       
   958    * @var boolean
       
   959    */
       
   960   protected $prepared = FALSE;
       
   961 
       
   962   /**
       
   963    * The FOR UPDATE status
       
   964    */
       
   965   protected $forUpdate = FALSE;
       
   966 
       
   967   public function __construct($table, $alias = NULL, DatabaseConnection $connection, $options = array()) {
       
   968     $options['return'] = Database::RETURN_STATEMENT;
       
   969     parent::__construct($connection, $options);
       
   970     $this->where = new DatabaseCondition('AND');
       
   971     $this->having = new DatabaseCondition('AND');
       
   972     $this->addJoin(NULL, $table, $alias);
       
   973   }
       
   974 
       
   975   /* Implementations of QueryAlterableInterface. */
       
   976 
       
   977   public function addTag($tag) {
       
   978     $this->alterTags[$tag] = 1;
       
   979     return $this;
       
   980   }
       
   981 
       
   982   public function hasTag($tag) {
       
   983     return isset($this->alterTags[$tag]);
       
   984   }
       
   985 
       
   986   public function hasAllTags() {
       
   987     $args = func_get_args();
       
   988     return !(boolean)array_diff($args, array_keys($this->alterTags));
       
   989   }
       
   990 
       
   991   public function hasAnyTag() {
       
   992     $args = func_get_args();
       
   993     return (boolean)array_intersect($args, array_keys($this->alterTags));
       
   994   }
       
   995 
       
   996   public function addMetaData($key, $object) {
       
   997     $this->alterMetaData[$key] = $object;
       
   998     return $this;
       
   999   }
       
  1000 
       
  1001   public function getMetaData($key) {
       
  1002     return isset($this->alterMetaData[$key]) ? $this->alterMetaData[$key] : NULL;
       
  1003   }
       
  1004 
       
  1005   /* Implementations of QueryConditionInterface for the WHERE clause. */
       
  1006 
       
  1007   public function condition($field, $value = NULL, $operator = NULL) {
       
  1008     $this->where->condition($field, $value, $operator);
       
  1009     return $this;
       
  1010   }
       
  1011 
       
  1012   public function &conditions() {
       
  1013     return $this->where->conditions();
       
  1014   }
       
  1015 
       
  1016   public function arguments() {
       
  1017     if (!$this->compiled()) {
       
  1018       return NULL;
       
  1019     }
       
  1020 
       
  1021     $args = $this->where->arguments() + $this->having->arguments();
       
  1022 
       
  1023     foreach ($this->tables as $table) {
       
  1024       if ($table['arguments']) {
       
  1025         $args += $table['arguments'];
       
  1026       }
       
  1027       // If this table is a subquery, grab its arguments recursively.
       
  1028       if ($table['table'] instanceof SelectQueryInterface) {
       
  1029         $args += $table['table']->arguments();
       
  1030       }
       
  1031     }
       
  1032 
       
  1033     foreach ($this->expressions as $expression) {
       
  1034       if ($expression['arguments']) {
       
  1035         $args += $expression['arguments'];
       
  1036       }
       
  1037     }
       
  1038 
       
  1039     // If there are any dependent queries to UNION,
       
  1040     // incorporate their arguments recursively.
       
  1041     foreach ($this->union as $union) {
       
  1042       $args += $union['query']->arguments();
       
  1043     }
       
  1044 
       
  1045     return $args;
       
  1046   }
       
  1047 
       
  1048   public function where($snippet, $args = array()) {
       
  1049     $this->where->where($snippet, $args);
       
  1050     return $this;
       
  1051   }
       
  1052 
       
  1053   public function isNull($field) {
       
  1054     $this->where->isNull($field);
       
  1055     return $this;
       
  1056   }
       
  1057 
       
  1058   public function isNotNull($field) {
       
  1059     $this->where->isNotNull($field);
       
  1060     return $this;
       
  1061   }
       
  1062 
       
  1063   public function exists(SelectQueryInterface $select) {
       
  1064     $this->where->exists($select);
       
  1065     return $this;
       
  1066   }
       
  1067 
       
  1068   public function notExists(SelectQueryInterface $select) {
       
  1069     $this->where->notExists($select);
       
  1070     return $this;
       
  1071   }
       
  1072 
       
  1073   public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder) {
       
  1074     $this->where->compile($connection, $queryPlaceholder);
       
  1075     $this->having->compile($connection, $queryPlaceholder);
       
  1076 
       
  1077     foreach ($this->tables as $table) {
       
  1078       // If this table is a subquery, compile it recursively.
       
  1079       if ($table['table'] instanceof SelectQueryInterface) {
       
  1080         $table['table']->compile($connection, $queryPlaceholder);
       
  1081       }
       
  1082     }
       
  1083 
       
  1084     // If there are any dependent queries to UNION, compile it recursively.
       
  1085     foreach ($this->union as $union) {
       
  1086       $union['query']->compile($connection, $queryPlaceholder);
       
  1087     }
       
  1088   }
       
  1089 
       
  1090   public function compiled() {
       
  1091     if (!$this->where->compiled() || !$this->having->compiled()) {
       
  1092       return FALSE;
       
  1093     }
       
  1094 
       
  1095     foreach ($this->tables as $table) {
       
  1096       // If this table is a subquery, check its status recursively.
       
  1097       if ($table['table'] instanceof SelectQueryInterface) {
       
  1098         if (!$table['table']->compiled()) {
       
  1099           return FALSE;
       
  1100         }
       
  1101       }
       
  1102     }
       
  1103 
       
  1104     foreach ($this->union as $union) {
       
  1105       if (!$union['query']->compiled()) {
       
  1106         return FALSE;
       
  1107       }
       
  1108     }
       
  1109 
       
  1110     return TRUE;
       
  1111   }
       
  1112 
       
  1113   /* Implementations of QueryConditionInterface for the HAVING clause. */
       
  1114 
       
  1115   public function havingCondition($field, $value = NULL, $operator = NULL) {
       
  1116     $this->having->condition($field, $value, $operator);
       
  1117     return $this;
       
  1118   }
       
  1119 
       
  1120   public function &havingConditions() {
       
  1121     return $this->having->conditions();
       
  1122   }
       
  1123 
       
  1124   public function havingArguments() {
       
  1125     return $this->having->arguments();
       
  1126   }
       
  1127 
       
  1128   public function having($snippet, $args = array()) {
       
  1129     $this->having->where($snippet, $args);
       
  1130     return $this;
       
  1131   }
       
  1132 
       
  1133   public function havingCompile(DatabaseConnection $connection) {
       
  1134     return $this->having->compile($connection, $this);
       
  1135   }
       
  1136 
       
  1137   /* Implementations of QueryExtendableInterface. */
       
  1138 
       
  1139   public function extend($extender_name) {
       
  1140     $override_class = $extender_name . '_' . $this->connection->driver();
       
  1141     if (class_exists($override_class)) {
       
  1142       $extender_name = $override_class;
       
  1143     }
       
  1144     return new $extender_name($this, $this->connection);
       
  1145   }
       
  1146 
       
  1147   public function havingIsNull($field) {
       
  1148     $this->having->isNull($field);
       
  1149     return $this;
       
  1150   }
       
  1151 
       
  1152   public function havingIsNotNull($field) {
       
  1153     $this->having->isNotNull($field);
       
  1154     return $this;
       
  1155   }
       
  1156 
       
  1157   public function havingExists(SelectQueryInterface $select) {
       
  1158     $this->having->exists($select);
       
  1159     return $this;
       
  1160   }
       
  1161 
       
  1162   public function havingNotExists(SelectQueryInterface $select) {
       
  1163     $this->having->notExists($select);
       
  1164     return $this;
       
  1165   }
       
  1166 
       
  1167   public function forUpdate($set = TRUE) {
       
  1168     if (isset($set)) {
       
  1169       $this->forUpdate = $set;
       
  1170     }
       
  1171     return $this;
       
  1172   }
       
  1173 
       
  1174   /* Alter accessors to expose the query data to alter hooks. */
       
  1175 
       
  1176   public function &getFields() {
       
  1177     return $this->fields;
       
  1178   }
       
  1179 
       
  1180   public function &getExpressions() {
       
  1181     return $this->expressions;
       
  1182   }
       
  1183 
       
  1184   public function &getOrderBy() {
       
  1185     return $this->order;
       
  1186   }
       
  1187 
       
  1188   public function &getGroupBy() {
       
  1189     return $this->group;
       
  1190   }
       
  1191 
       
  1192   public function &getTables() {
       
  1193     return $this->tables;
       
  1194   }
       
  1195 
       
  1196   public function &getUnion() {
       
  1197     return $this->union;
       
  1198   }
       
  1199 
       
  1200   public function getArguments(QueryPlaceholderInterface $queryPlaceholder = NULL) {
       
  1201     if (!isset($queryPlaceholder)) {
       
  1202       $queryPlaceholder = $this;
       
  1203     }
       
  1204     $this->compile($this->connection, $queryPlaceholder);
       
  1205     return $this->arguments();
       
  1206   }
       
  1207 
       
  1208   /**
       
  1209    * Indicates if preExecute() has already been called on that object.
       
  1210    */
       
  1211   public function isPrepared() {
       
  1212     return $this->prepared;
       
  1213   }
       
  1214 
       
  1215   /**
       
  1216    * Generic preparation and validation for a SELECT query.
       
  1217    *
       
  1218    * @return
       
  1219    *   TRUE if the validation was successful, FALSE if not.
       
  1220    */
       
  1221   public function preExecute(SelectQueryInterface $query = NULL) {
       
  1222     // If no query object is passed in, use $this.
       
  1223     if (!isset($query)) {
       
  1224       $query = $this;
       
  1225     }
       
  1226 
       
  1227     // Only execute this once.
       
  1228     if ($query->isPrepared()) {
       
  1229       return TRUE;
       
  1230     }
       
  1231 
       
  1232     // Modules may alter all queries or only those having a particular tag.
       
  1233     if (isset($this->alterTags)) {
       
  1234       // Many contrib modules assume that query tags used for access-checking
       
  1235       // purposes follow the pattern $entity_type . '_access'. But this is
       
  1236       // not the case for taxonomy terms, since core used to add term_access
       
  1237       // instead of taxonomy_term_access to its queries. Provide backwards
       
  1238       // compatibility by adding both tags here instead of attempting to fix
       
  1239       // all contrib modules in a coordinated effort.
       
  1240       // TODO:
       
  1241       // - Extract this mechanism into a hook as part of a public (non-security)
       
  1242       //   issue.
       
  1243       // - Emit E_USER_DEPRECATED if term_access is used.
       
  1244       //   https://www.drupal.org/node/2575081
       
  1245       $term_access_tags = array('term_access' => 1, 'taxonomy_term_access' => 1);
       
  1246       if (array_intersect_key($this->alterTags, $term_access_tags)) {
       
  1247         $this->alterTags += $term_access_tags;
       
  1248       }
       
  1249       $hooks = array('query');
       
  1250       foreach ($this->alterTags as $tag => $value) {
       
  1251         $hooks[] = 'query_' . $tag;
       
  1252       }
       
  1253       drupal_alter($hooks, $query);
       
  1254     }
       
  1255 
       
  1256     $this->prepared = TRUE;
       
  1257 
       
  1258     // Now also prepare any sub-queries.
       
  1259     foreach ($this->tables as $table) {
       
  1260       if ($table['table'] instanceof SelectQueryInterface) {
       
  1261         $table['table']->preExecute();
       
  1262       }
       
  1263     }
       
  1264 
       
  1265     foreach ($this->union as $union) {
       
  1266       $union['query']->preExecute();
       
  1267     }
       
  1268 
       
  1269     return $this->prepared;
       
  1270   }
       
  1271 
       
  1272   public function execute() {
       
  1273     // If validation fails, simply return NULL.
       
  1274     // Note that validation routines in preExecute() may throw exceptions instead.
       
  1275     if (!$this->preExecute()) {
       
  1276       return NULL;
       
  1277     }
       
  1278 
       
  1279     $args = $this->getArguments();
       
  1280     return $this->connection->query((string) $this, $args, $this->queryOptions);
       
  1281   }
       
  1282 
       
  1283   public function distinct($distinct = TRUE) {
       
  1284     $this->distinct = $distinct;
       
  1285     return $this;
       
  1286   }
       
  1287 
       
  1288   public function addField($table_alias, $field, $alias = NULL) {
       
  1289     // If no alias is specified, first try the field name itself.
       
  1290     if (empty($alias)) {
       
  1291       $alias = $field;
       
  1292     }
       
  1293 
       
  1294     // If that's already in use, try the table name and field name.
       
  1295     if (!empty($this->fields[$alias])) {
       
  1296       $alias = $table_alias . '_' . $field;
       
  1297     }
       
  1298 
       
  1299     // If that is already used, just add a counter until we find an unused alias.
       
  1300     $alias_candidate = $alias;
       
  1301     $count = 2;
       
  1302     while (!empty($this->fields[$alias_candidate])) {
       
  1303       $alias_candidate = $alias . '_' . $count++;
       
  1304     }
       
  1305     $alias = $alias_candidate;
       
  1306 
       
  1307     $this->fields[$alias] = array(
       
  1308       'field' => $field,
       
  1309       'table' => $table_alias,
       
  1310       'alias' => $alias,
       
  1311     );
       
  1312 
       
  1313     return $alias;
       
  1314   }
       
  1315 
       
  1316   public function fields($table_alias, array $fields = array()) {
       
  1317 
       
  1318     if ($fields) {
       
  1319       foreach ($fields as $field) {
       
  1320         // We don't care what alias was assigned.
       
  1321         $this->addField($table_alias, $field);
       
  1322       }
       
  1323     }
       
  1324     else {
       
  1325       // We want all fields from this table.
       
  1326       $this->tables[$table_alias]['all_fields'] = TRUE;
       
  1327     }
       
  1328 
       
  1329     return $this;
       
  1330   }
       
  1331 
       
  1332   public function addExpression($expression, $alias = NULL, $arguments = array()) {
       
  1333     if (empty($alias)) {
       
  1334       $alias = 'expression';
       
  1335     }
       
  1336 
       
  1337     $alias_candidate = $alias;
       
  1338     $count = 2;
       
  1339     while (!empty($this->expressions[$alias_candidate])) {
       
  1340       $alias_candidate = $alias . '_' . $count++;
       
  1341     }
       
  1342     $alias = $alias_candidate;
       
  1343 
       
  1344     $this->expressions[$alias] = array(
       
  1345       'expression' => $expression,
       
  1346       'alias' => $alias,
       
  1347       'arguments' => $arguments,
       
  1348     );
       
  1349 
       
  1350     return $alias;
       
  1351   }
       
  1352 
       
  1353   public function join($table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
  1354     return $this->addJoin('INNER', $table, $alias, $condition, $arguments);
       
  1355   }
       
  1356 
       
  1357   public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
  1358     return $this->addJoin('INNER', $table, $alias, $condition, $arguments);
       
  1359   }
       
  1360 
       
  1361   public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
  1362     return $this->addJoin('LEFT OUTER', $table, $alias, $condition, $arguments);
       
  1363   }
       
  1364 
       
  1365   public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
  1366     return $this->addJoin('RIGHT OUTER', $table, $alias, $condition, $arguments);
       
  1367   }
       
  1368 
       
  1369   public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array()) {
       
  1370 
       
  1371     if (empty($alias)) {
       
  1372       if ($table instanceof SelectQueryInterface) {
       
  1373         $alias = 'subquery';
       
  1374       }
       
  1375       else {
       
  1376         $alias = $table;
       
  1377       }
       
  1378     }
       
  1379 
       
  1380     $alias_candidate = $alias;
       
  1381     $count = 2;
       
  1382     while (!empty($this->tables[$alias_candidate])) {
       
  1383       $alias_candidate = $alias . '_' . $count++;
       
  1384     }
       
  1385     $alias = $alias_candidate;
       
  1386 
       
  1387     if (is_string($condition)) {
       
  1388       $condition = str_replace('%alias', $alias, $condition);
       
  1389     }
       
  1390 
       
  1391     $this->tables[$alias] = array(
       
  1392       'join type' => $type,
       
  1393       'table' => $table,
       
  1394       'alias' => $alias,
       
  1395       'condition' => $condition,
       
  1396       'arguments' => $arguments,
       
  1397     );
       
  1398 
       
  1399     return $alias;
       
  1400   }
       
  1401 
       
  1402   public function orderBy($field, $direction = 'ASC') {
       
  1403     // Only allow ASC and DESC, default to ASC.
       
  1404     $direction = strtoupper($direction) == 'DESC' ? 'DESC' : 'ASC';
       
  1405     $this->order[$field] = $direction;
       
  1406     return $this;
       
  1407   }
       
  1408 
       
  1409   public function orderRandom() {
       
  1410     $alias = $this->addExpression('RAND()', 'random_field');
       
  1411     $this->orderBy($alias);
       
  1412     return $this;
       
  1413   }
       
  1414 
       
  1415   public function range($start = NULL, $length = NULL) {
       
  1416     $this->range = func_num_args() ? array('start' => $start, 'length' => $length) : array();
       
  1417     return $this;
       
  1418   }
       
  1419 
       
  1420   public function union(SelectQueryInterface $query, $type = '') {
       
  1421     // Handle UNION aliasing.
       
  1422     switch ($type) {
       
  1423       // Fold UNION DISTINCT to UNION for better cross database support.
       
  1424       case 'DISTINCT':
       
  1425       case '':
       
  1426         $type = 'UNION';
       
  1427         break;
       
  1428 
       
  1429       case 'ALL':
       
  1430         $type = 'UNION ALL';
       
  1431       default:
       
  1432     }
       
  1433 
       
  1434     $this->union[] = array(
       
  1435       'type' => $type,
       
  1436       'query' => $query,
       
  1437     );
       
  1438 
       
  1439     return $this;
       
  1440   }
       
  1441 
       
  1442   public function groupBy($field) {
       
  1443     $this->group[$field] = $field;
       
  1444     return $this;
       
  1445   }
       
  1446 
       
  1447   public function countQuery() {
       
  1448     // Create our new query object that we will mutate into a count query.
       
  1449     $count = clone($this);
       
  1450 
       
  1451     $group_by = $count->getGroupBy();
       
  1452     $having = $count->havingConditions();
       
  1453 
       
  1454     if (!$count->distinct && !isset($having[0])) {
       
  1455       // When not executing a distinct query, we can zero-out existing fields
       
  1456       // and expressions that are not used by a GROUP BY or HAVING. Fields
       
  1457       // listed in a GROUP BY or HAVING clause need to be present in the
       
  1458       // query.
       
  1459       $fields =& $count->getFields();
       
  1460       foreach (array_keys($fields) as $field) {
       
  1461         if (empty($group_by[$field])) {
       
  1462           unset($fields[$field]);
       
  1463         }
       
  1464       }
       
  1465 
       
  1466       $expressions =& $count->getExpressions();
       
  1467       foreach (array_keys($expressions) as $field) {
       
  1468         if (empty($group_by[$field])) {
       
  1469           unset($expressions[$field]);
       
  1470         }
       
  1471       }
       
  1472 
       
  1473       // Also remove 'all_fields' statements, which are expanded into tablename.*
       
  1474       // when the query is executed.
       
  1475       foreach ($count->tables as $alias => &$table) {
       
  1476         unset($table['all_fields']);
       
  1477       }
       
  1478     }
       
  1479 
       
  1480     // If we've just removed all fields from the query, make sure there is at
       
  1481     // least one so that the query still runs.
       
  1482     $count->addExpression('1');
       
  1483 
       
  1484     // Ordering a count query is a waste of cycles, and breaks on some
       
  1485     // databases anyway.
       
  1486     $orders = &$count->getOrderBy();
       
  1487     $orders = array();
       
  1488 
       
  1489     if ($count->distinct && !empty($group_by)) {
       
  1490       // If the query is distinct and contains a GROUP BY, we need to remove the
       
  1491       // distinct because SQL99 does not support counting on distinct multiple fields.
       
  1492       $count->distinct = FALSE;
       
  1493     }
       
  1494 
       
  1495     $query = $this->connection->select($count);
       
  1496     $query->addExpression('COUNT(*)');
       
  1497 
       
  1498     return $query;
       
  1499   }
       
  1500 
       
  1501   public function __toString() {
       
  1502     // For convenience, we compile the query ourselves if the caller forgot
       
  1503     // to do it. This allows constructs like "(string) $query" to work. When
       
  1504     // the query will be executed, it will be recompiled using the proper
       
  1505     // placeholder generator anyway.
       
  1506     if (!$this->compiled()) {
       
  1507       $this->compile($this->connection, $this);
       
  1508     }
       
  1509 
       
  1510     // Create a sanitized comment string to prepend to the query.
       
  1511     $comments = $this->connection->makeComment($this->comments);
       
  1512 
       
  1513     // SELECT
       
  1514     $query = $comments . 'SELECT ';
       
  1515     if ($this->distinct) {
       
  1516       $query .= 'DISTINCT ';
       
  1517     }
       
  1518 
       
  1519     // FIELDS and EXPRESSIONS
       
  1520     $fields = array();
       
  1521     foreach ($this->tables as $alias => $table) {
       
  1522       if (!empty($table['all_fields'])) {
       
  1523         $fields[] = $this->connection->escapeTable($alias) . '.*';
       
  1524       }
       
  1525     }
       
  1526     foreach ($this->fields as $alias => $field) {
       
  1527       // Always use the AS keyword for field aliases, as some
       
  1528       // databases require it (e.g., PostgreSQL).
       
  1529       $fields[] = (isset($field['table']) ? $this->connection->escapeTable($field['table']) . '.' : '') . $this->connection->escapeField($field['field']) . ' AS ' . $this->connection->escapeAlias($field['alias']);
       
  1530     }
       
  1531     foreach ($this->expressions as $alias => $expression) {
       
  1532       $fields[] = $expression['expression'] . ' AS ' . $this->connection->escapeAlias($expression['alias']);
       
  1533     }
       
  1534     $query .= implode(', ', $fields);
       
  1535 
       
  1536 
       
  1537     // FROM - We presume all queries have a FROM, as any query that doesn't won't need the query builder anyway.
       
  1538     $query .= "\nFROM ";
       
  1539     foreach ($this->tables as $alias => $table) {
       
  1540       $query .= "\n";
       
  1541       if (isset($table['join type'])) {
       
  1542         $query .= $table['join type'] . ' JOIN ';
       
  1543       }
       
  1544 
       
  1545       // If the table is a subquery, compile it and integrate it into this query.
       
  1546       if ($table['table'] instanceof SelectQueryInterface) {
       
  1547         // Run preparation steps on this sub-query before converting to string.
       
  1548         $subquery = $table['table'];
       
  1549         $subquery->preExecute();
       
  1550         $table_string = '(' . (string) $subquery . ')';
       
  1551       }
       
  1552       else {
       
  1553         $table_string = '{' . $this->connection->escapeTable($table['table']) . '}';
       
  1554       }
       
  1555 
       
  1556       // Don't use the AS keyword for table aliases, as some
       
  1557       // databases don't support it (e.g., Oracle).
       
  1558       $query .=  $table_string . ' ' . $this->connection->escapeTable($table['alias']);
       
  1559 
       
  1560       if (!empty($table['condition'])) {
       
  1561         $query .= ' ON ' . $table['condition'];
       
  1562       }
       
  1563     }
       
  1564 
       
  1565     // WHERE
       
  1566     if (count($this->where)) {
       
  1567       // There is an implicit string cast on $this->condition.
       
  1568       $query .= "\nWHERE " . $this->where;
       
  1569     }
       
  1570 
       
  1571     // GROUP BY
       
  1572     if ($this->group) {
       
  1573       $query .= "\nGROUP BY " . implode(', ', $this->group);
       
  1574     }
       
  1575 
       
  1576     // HAVING
       
  1577     if (count($this->having)) {
       
  1578       // There is an implicit string cast on $this->having.
       
  1579       $query .= "\nHAVING " . $this->having;
       
  1580     }
       
  1581 
       
  1582     // ORDER BY
       
  1583     if ($this->order) {
       
  1584       $query .= "\nORDER BY ";
       
  1585       $fields = array();
       
  1586       foreach ($this->order as $field => $direction) {
       
  1587         $fields[] = $field . ' ' . $direction;
       
  1588       }
       
  1589       $query .= implode(', ', $fields);
       
  1590     }
       
  1591 
       
  1592     // RANGE
       
  1593     // There is no universal SQL standard for handling range or limit clauses.
       
  1594     // Fortunately, all core-supported databases use the same range syntax.
       
  1595     // Databases that need a different syntax can override this method and
       
  1596     // do whatever alternate logic they need to.
       
  1597     if (!empty($this->range)) {
       
  1598       $query .= "\nLIMIT " . (int) $this->range['length'] . " OFFSET " . (int) $this->range['start'];
       
  1599     }
       
  1600 
       
  1601     // UNION is a little odd, as the select queries to combine are passed into
       
  1602     // this query, but syntactically they all end up on the same level.
       
  1603     if ($this->union) {
       
  1604       foreach ($this->union as $union) {
       
  1605         $query .= ' ' . $union['type'] . ' ' . (string) $union['query'];
       
  1606       }
       
  1607     }
       
  1608 
       
  1609     if ($this->forUpdate) {
       
  1610       $query .= ' FOR UPDATE';
       
  1611     }
       
  1612 
       
  1613     return $query;
       
  1614   }
       
  1615 
       
  1616   public function __clone() {
       
  1617     // On cloning, also clone the dependent objects. However, we do not
       
  1618     // want to clone the database connection object as that would duplicate the
       
  1619     // connection itself.
       
  1620 
       
  1621     $this->where = clone($this->where);
       
  1622     $this->having = clone($this->having);
       
  1623     foreach ($this->union as $key => $aggregate) {
       
  1624       $this->union[$key]['query'] = clone($aggregate['query']);
       
  1625     }
       
  1626   }
       
  1627 }
       
  1628 
       
  1629 /**
       
  1630  * @} End of "addtogroup database".
       
  1631  */