Skip to content

Commit fa5205c

Browse files
author
Mateu Aguiló Bosch
committed
[BUGFIX] Avoid INNER JOIN for LEFT JOIN filters
If the first field condition (alphabetically) is a LEFT JOIN filter, make sure that subsequent fields do not join to it with an INNER JOIN.
1 parent 7c956e5 commit fa5205c

File tree

2 files changed

+41
-11
lines changed

2 files changed

+41
-11
lines changed

src/Plugin/resource/DataProvider/DataProvider.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ public static function processFilterInput($filter, $public_field) {
9797
$filter = array('value' => $filter);
9898
}
9999
if (!is_array($filter['value'])) {
100+
if (!isset($filter['value'])) {
101+
throw new BadRequestException(sprintf('Value not present for the "%s" filter. Please check the URL format.', $public_field));
102+
}
100103
$filter['value'] = array($filter['value']);
101104
}
102105
// Add the property.

src/Util/EntityFieldQuery.php

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -309,13 +309,14 @@ protected function fieldStorageQuery(SelectQuery $select_query) {
309309
$base_table = $this->metaData['base_table'];
310310

311311
// Add tables for the fields used.
312+
$field_base_table = NULL;
312313
foreach ($this->fields as $key => $field) {
313314
$tablename = $tablename_function($field);
314315
$table_alias = _field_sql_storage_tablealias($tablename, $key, $this);
315316
$table_aliases[$key] = $table_alias;
316317
$select_query->addMetaData('base_table', $base_table);
317318
$entity_id_key = $this->metaData['entity_id_key'];
318-
if ($key) {
319+
if ($field_base_table) {
319320
if (!isset($query_tables[$table_alias])) {
320321
$this->addFieldJoin($select_query, $field['field_name'], $tablename, $table_alias, "$table_alias.entity_type = $field_base_table.entity_type AND $table_alias.$id_key = $field_base_table.$id_key");
321322
}
@@ -332,7 +333,9 @@ protected function fieldStorageQuery(SelectQuery $select_query) {
332333
if (!isset($this->tags['DANGEROUS_ACCESS_CHECK_OPT_OUT'])) {
333334
$select_query->addTag('entity_field_access');
334335
}
335-
$field_base_table = $table_alias;
336+
if (!$this->containsLeftJoinOperator($this->fields[$key]['field_name'])) {
337+
$field_base_table = $table_alias;
338+
}
336339
}
337340
if ($field['cardinality'] != 1 || $field['translatable']) {
338341
$select_query->distinct();
@@ -346,13 +349,15 @@ protected function fieldStorageQuery(SelectQuery $select_query) {
346349
// Add field meta conditions.
347350
_field_sql_storage_query_field_conditions($this, $select_query, $this->fieldMetaConditions, $table_aliases, '_field_sql_storage_query_columnname');
348351

349-
// Find out if the query needs the OR.
352+
// If there was no field condition that created an INNER JOIN, that means
353+
// that additional JOINs need to carry the OR condition. For the base table
354+
// we'll use the table for the first field.
350355
$needs_or = FALSE;
351-
foreach ($this->fieldConditions as $field_condition) {
352-
if ($field_condition['field']['field_name'] != $this->fields[0]['field_name']) {
353-
continue;
354-
}
355-
$needs_or = in_array($field_condition['operator'], static::$leftJoinOperators);
356+
if (!isset($field_base_table)) {
357+
$needs_or = TRUE;
358+
// Get the table name for the first field.
359+
$field_table_name = key($this->fields[0]['storage']['details']['sql'][$this->age]);
360+
$field_base_table = _field_sql_storage_tablealias($field_table_name, 0, $this);
356361
}
357362

358363
if (isset($this->deleted)) {
@@ -454,10 +459,32 @@ public function addCondition(SelectQuery $select_query, $sql_field, $condition,
454459
return;
455460
}
456461
$method = $having ? 'havingCondition' : 'condition';
457-
$db_or = db_or()
458-
->condition($sql_field, $condition['value'], $condition['operator'])
459-
->condition($sql_field, NULL, 'IS NULL');
462+
$db_or = db_or()->condition($sql_field, $condition['value'], $condition['operator']);
463+
if (strtoupper($condition['operator']) != 'IS NULL' && strtoupper($condition['operator']) != 'IS NOT NULL') {
464+
$db_or->condition($sql_field, NULL, 'IS NULL');
465+
}
460466
$select_query->$method($db_or);
461467
}
462468

469+
/**
470+
* Checks if any of the conditions contains a LEFT JOIN operation.
471+
*
472+
* @param string $field_name
473+
* If provided only this field will be checked.
474+
*
475+
* @return bool
476+
* TRUE if any of the conditions contain a left join operator.
477+
*/
478+
protected function containsLeftJoinOperator($field_name = NULL) {
479+
foreach ($this->fieldConditions as $field_condition) {
480+
if ($field_name && $field_condition['field']['field_name'] != $field_name) {
481+
continue;
482+
}
483+
if (in_array($field_condition['operator'], static::$leftJoinOperators)) {
484+
return TRUE;
485+
}
486+
}
487+
return FALSE;
488+
}
489+
463490
}

0 commit comments

Comments
 (0)