diff options
-rw-r--r-- | includes/database/select.inc | 60 | ||||
-rw-r--r-- | modules/field/field.multilingual.inc | 7 | ||||
-rw-r--r-- | modules/field/tests/field.test | 10 | ||||
-rw-r--r-- | modules/field/tests/field_test.module | 4 | ||||
-rw-r--r-- | modules/simpletest/tests/database_test.test | 13 |
5 files changed, 78 insertions, 16 deletions
diff --git a/includes/database/select.inc b/includes/database/select.inc index 535c29c85..d46abefdf 100644 --- a/includes/database/select.inc +++ b/includes/database/select.inc @@ -94,6 +94,24 @@ interface SelectQueryInterface extends QueryConditionInterface, QueryAlterableIn 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. * * Because this method returns by reference, alter hooks may edit the tables @@ -619,6 +637,10 @@ class SelectQueryExtender implements SelectQueryInterface { return $this->query->getOrderBy(); } + public function &getGroupBy() { + return $this->query->getGroupBy(); + } + public function &getTables() { return $this->query->getTables(); } @@ -1026,6 +1048,10 @@ class SelectQuery extends Query implements SelectQueryInterface { return $this->order; } + public function &getGroupBy() { + return $this->group; + } + public function &getTables() { 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. $count = clone($this); + $group_by = array_keys($count->getGroupBy()); + if (!$count->distinct) { // 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 = array(); + foreach (array_keys($fields) as $field) { + if (!empty($group_by[$field])) { + unset($fields[$field]); + } + } $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.* // 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 // databases anyway. $orders = &$count->getOrderBy(); $orders = array(); - if ($count->distinct) { - // If the query is distinct, we need to execute it in a subquery, - // because SQL99 does not support counting on distinct multiple fields. - $count = db_select($count); + if ($count->distinct && !empty($group_by)) { + // If the query is distinct and contains a GROUP BY, we need to remove the + // distinct because SQL99 does not support counting on distinct multiple fields. $count->distinct = FALSE; } - // COUNT() is an expression, so we add that back in. - $count->addExpression('COUNT(*)'); + $query = db_select($count); + $query->addExpression('COUNT(*)'); - return $count; + return $query; } public function __toString() { diff --git a/modules/field/field.multilingual.inc b/modules/field/field.multilingual.inc index e0b134849..600ed3010 100644 --- a/modules/field/field.multilingual.inc +++ b/modules/field/field.multilingual.inc @@ -216,10 +216,11 @@ function field_language($entity_type, $entity, $field_name = NULL, $langcode = N if (!isset($display_languages[$entity_type][$id][$langcode])) { $display_language = array(); - // By default display language is set to LANGUAGE_NONE. It is up to - // translation handlers to implement language fallback rules. + // By default display language is set to LANGUAGE_NONE if the field + // translation is not available. It is up to translation handlers to + // implement language fallback rules. 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)) { diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test index 7fbdba694..479b0a966 100644 --- a/modules/field/tests/field.test +++ b/modules/field/tests/field.test @@ -2639,8 +2639,7 @@ class FieldTranslationsTestCase extends FieldTestCase { field_create_instance($instance); $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, $bundle); + $instances = field_info_instances($entity_type, $this->instance['bundle']); $enabled_languages = field_content_languages(); $languages = array(); @@ -2688,6 +2687,13 @@ class FieldTranslationsTestCase extends FieldTestCase { drupal_static_reset('field_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))); + + // 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')); } /** diff --git a/modules/field/tests/field_test.module b/modules/field/tests/field_test.module index 2eac091e2..f615129ff 100644 --- a/modules/field/tests/field_test.module +++ b/modules/field/tests/field_test.module @@ -103,7 +103,9 @@ function field_test_field_available_languages_alter(&$languages, $context) { * Implements hook_field_language_alter(). */ 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']); + } } /** diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test index b2efa6672..e7f812893 100644 --- a/modules/simpletest/tests/database_test.test +++ b/modules/simpletest/tests/database_test.test @@ -1987,6 +1987,19 @@ class DatabaseSelectComplexTestCase extends DatabaseTestCase { } /** + * 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. */ function testNestedConditions() { |