- Patch #423888 by mikeryan, Crell, drunken monkey: use subqueries for ->countQuery(), at least for MySQL.
parent
a9c9ef2d30
commit
66d31c52ba
|
@ -93,6 +93,24 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn
|
||||||
*/
|
*/
|
||||||
public function &getOrderBy();
|
public function &getOrderBy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a reference to the group-by array for this query.
|
||||||
|
*
|
||||||
|
* Because this method returns by reference, alter hooks may edit the group-by
|
||||||
|
* array directly to make their changes. If just adding additional grouping
|
||||||
|
* fields, however, the use of groupBy() is preferred.
|
||||||
|
*
|
||||||
|
* Note that this method must be called by reference as well:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* $fields =& $query->getGroupBy();
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A reference to the group-by array structure.
|
||||||
|
*/
|
||||||
|
public function &getGroupBy();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a reference to the tables array for this query.
|
* Returns a reference to the tables array for this query.
|
||||||
*
|
*
|
||||||
|
@ -619,6 +637,10 @@ class SelectQueryExtender implements SelectQueryInterface {
|
||||||
return $this->query->getOrderBy();
|
return $this->query->getOrderBy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function &getGroupBy() {
|
||||||
|
return $this->query->getGroupBy();
|
||||||
|
}
|
||||||
|
|
||||||
public function &getTables() {
|
public function &getTables() {
|
||||||
return $this->query->getTables();
|
return $this->query->getTables();
|
||||||
}
|
}
|
||||||
|
@ -1026,6 +1048,10 @@ class SelectQuery extends Query implements SelectQueryInterface {
|
||||||
return $this->order;
|
return $this->order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function &getGroupBy() {
|
||||||
|
return $this->group;
|
||||||
|
}
|
||||||
|
|
||||||
public function &getTables() {
|
public function &getTables() {
|
||||||
return $this->tables;
|
return $this->tables;
|
||||||
}
|
}
|
||||||
|
@ -1279,13 +1305,24 @@ class SelectQuery extends Query implements SelectQueryInterface {
|
||||||
// Create our new query object that we will mutate into a count query.
|
// Create our new query object that we will mutate into a count query.
|
||||||
$count = clone($this);
|
$count = clone($this);
|
||||||
|
|
||||||
|
$group_by = array_keys($count->getGroupBy());
|
||||||
|
|
||||||
if (!$count->distinct) {
|
if (!$count->distinct) {
|
||||||
// When not executing a distinct query, we can zero-out existing fields
|
// When not executing a distinct query, we can zero-out existing fields
|
||||||
// and expressions.
|
// and expressions that are not used by a GROUP BY. Fields listed in
|
||||||
|
// the GROUP BY clause need to be present in the query.
|
||||||
$fields =& $count->getFields();
|
$fields =& $count->getFields();
|
||||||
$fields = array();
|
foreach (array_keys($fields) as $field) {
|
||||||
|
if (!empty($group_by[$field])) {
|
||||||
|
unset($fields[$field]);
|
||||||
|
}
|
||||||
|
}
|
||||||
$expressions =& $count->getExpressions();
|
$expressions =& $count->getExpressions();
|
||||||
$expressions = array();
|
foreach (array_keys($expressions) as $field) {
|
||||||
|
if (!empty($group_by[$field])) {
|
||||||
|
unset($fields[$field]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Also remove 'all_fields' statements, which are expanded into tablename.*
|
// Also remove 'all_fields' statements, which are expanded into tablename.*
|
||||||
// when the query is executed.
|
// when the query is executed.
|
||||||
|
@ -1294,22 +1331,25 @@ class SelectQuery extends Query implements SelectQueryInterface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we've just removed all fields from the query, make sure there is at
|
||||||
|
// least one so that the query still runs.
|
||||||
|
$count->addExpression('1');
|
||||||
|
|
||||||
// Ordering a count query is a waste of cycles, and breaks on some
|
// Ordering a count query is a waste of cycles, and breaks on some
|
||||||
// databases anyway.
|
// databases anyway.
|
||||||
$orders = &$count->getOrderBy();
|
$orders = &$count->getOrderBy();
|
||||||
$orders = array();
|
$orders = array();
|
||||||
|
|
||||||
if ($count->distinct) {
|
if ($count->distinct && !empty($group_by)) {
|
||||||
// If the query is distinct, we need to execute it in a subquery,
|
// If the query is distinct and contains a GROUP BY, we need to remove the
|
||||||
// because SQL99 does not support counting on distinct multiple fields.
|
// distinct because SQL99 does not support counting on distinct multiple fields.
|
||||||
$count = db_select($count);
|
|
||||||
$count->distinct = FALSE;
|
$count->distinct = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// COUNT() is an expression, so we add that back in.
|
$query = db_select($count);
|
||||||
$count->addExpression('COUNT(*)');
|
$query->addExpression('COUNT(*)');
|
||||||
|
|
||||||
return $count;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __toString() {
|
public function __toString() {
|
||||||
|
|
|
@ -216,10 +216,11 @@ function field_language($entity_type, $entity, $field_name = NULL, $langcode = N
|
||||||
if (!isset($display_languages[$entity_type][$id][$langcode])) {
|
if (!isset($display_languages[$entity_type][$id][$langcode])) {
|
||||||
$display_language = array();
|
$display_language = array();
|
||||||
|
|
||||||
// By default display language is set to LANGUAGE_NONE. It is up to
|
// By default display language is set to LANGUAGE_NONE if the field
|
||||||
// translation handlers to implement language fallback rules.
|
// translation is not available. It is up to translation handlers to
|
||||||
|
// implement language fallback rules.
|
||||||
foreach (field_info_instances($entity_type, $bundle) as $instance) {
|
foreach (field_info_instances($entity_type, $bundle) as $instance) {
|
||||||
$display_language[$instance['field_name']] = LANGUAGE_NONE;
|
$display_language[$instance['field_name']] = isset($entity->{$instance['field_name']}[$langcode]) ? $langcode : LANGUAGE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field_has_translation_handler($entity_type)) {
|
if (field_has_translation_handler($entity_type)) {
|
||||||
|
|
|
@ -2639,8 +2639,7 @@ class FieldTranslationsTestCase extends FieldTestCase {
|
||||||
field_create_instance($instance);
|
field_create_instance($instance);
|
||||||
|
|
||||||
$entity = field_test_create_stub_entity(1, 1, $this->instance['bundle']);
|
$entity = field_test_create_stub_entity(1, 1, $this->instance['bundle']);
|
||||||
list(, , $bundle) = entity_extract_ids($entity_type, $entity);
|
$instances = field_info_instances($entity_type, $this->instance['bundle']);
|
||||||
$instances = field_info_instances($entity_type, $bundle);
|
|
||||||
|
|
||||||
$enabled_languages = field_content_languages();
|
$enabled_languages = field_content_languages();
|
||||||
$languages = array();
|
$languages = array();
|
||||||
|
@ -2688,6 +2687,13 @@ class FieldTranslationsTestCase extends FieldTestCase {
|
||||||
drupal_static_reset('field_language');
|
drupal_static_reset('field_language');
|
||||||
$langcode = field_language($entity_type, $entity, $this->field_name, $requested_language);
|
$langcode = field_language($entity_type, $entity, $this->field_name, $requested_language);
|
||||||
$this->assertTrue(isset($entity->{$this->field_name}[$langcode]) && $langcode != $requested_language, t('The display language for the (single) field %field_name is %language.', array('%field_name' => $field_name, '%language' => $langcode)));
|
$this->assertTrue(isset($entity->{$this->field_name}[$langcode]) && $langcode != $requested_language, t('The display language for the (single) field %field_name is %language.', array('%field_name' => $field_name, '%language' => $langcode)));
|
||||||
|
|
||||||
|
// Test field_language() basic behavior without language fallback.
|
||||||
|
variable_set('field_test_language_fallback', FALSE);
|
||||||
|
$entity->{$this->field_name}[$requested_language] = mt_rand(1, 127);
|
||||||
|
drupal_static_reset('field_language');
|
||||||
|
$display_language = field_language($entity_type, $entity, $this->field_name, $requested_language);
|
||||||
|
$this->assertEqual($display_language, $requested_language, t('Display language behave correctly when language fallback is disabled'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -103,7 +103,9 @@ function field_test_field_available_languages_alter(&$languages, $context) {
|
||||||
* Implements hook_field_language_alter().
|
* Implements hook_field_language_alter().
|
||||||
*/
|
*/
|
||||||
function field_test_field_language_alter(&$display_language, $context) {
|
function field_test_field_language_alter(&$display_language, $context) {
|
||||||
locale_field_language_fallback($display_language, $context['entity'], $context['language']);
|
if (variable_get('field_test_language_fallback', TRUE)) {
|
||||||
|
locale_field_language_fallback($display_language, $context['entity'], $context['language']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1986,6 +1986,19 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase {
|
||||||
$this->assertEqual($count, 6, t('Counted the correct number of records.'));
|
$this->assertEqual($count, 6, t('Counted the correct number of records.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that we can generate a count query from a query with GROUP BY.
|
||||||
|
*/
|
||||||
|
function testCountQueryGroupBy() {
|
||||||
|
$query = db_select('test_task');
|
||||||
|
$pid_field = $query->addField('test_task', 'pid');
|
||||||
|
$query->groupBy('pid');
|
||||||
|
|
||||||
|
$count = $query->countQuery()->execute()->fetchField();
|
||||||
|
|
||||||
|
$this->assertEqual($count, 3, t('Counted the correct number of records.'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Confirm that we can properly nest conditional clauses.
|
* Confirm that we can properly nest conditional clauses.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue