Problem/Motivation

The advertised behavior of the JoinPluginBase is to permit operators other than '=' in the relationship:

<excerpted from core/modules/views/src/Plugin/views/join/JoinPluginBase.php>

 * Here are some examples of configuration for the join plugins.
 *
 * For this SQL:
 * @code
 * LEFT JOIN {two} ON one.field_a = two.field_b
 * @endcode
 * Use this configuration:
 * @code
 * $configuration = array(
 *   'table' => 'two',
 *   'field' => 'field_b',
 *   'left_table' => 'one',
 *   'left_field' => 'field_a',
 *   'operator' => '=',
 * );

However, the code ignores the operator directive - using '=' regardless of the configuration:

    $condition = "$left_field = $table[alias].$this->field";

While this might seem to be a critical bug on it's face, this actually is consistent with the views relationship handler in drupal 7 (see related issue), so, I mark it as "Normal", but given that the use description in the plugin code advertises this behavior it seems that it should be remedied.

Steps to reproduce

Proposed resolution

Add the configured operator to the condition

Remaining tasks

Review
Commit

User interface changes

API changes

Data model changes

Release notes snippet

Comments

robertwb created an issue. See original summary.

robertwb’s picture

Status: Active » Needs review
StatusFileSize
new823 bytes
robertwb’s picture

Linking D7 backport of this issue with patch.

lendude’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Not sure it I'd call this a bug, feels more like a feature (with a tiny bit of documentation already existing), but whatever.

No reason this shouldn't work as far as I can tell. This would need a fair amount of tests.

robertwb’s picture

Hey @Lendude thanks for the speedy review - I am guessing that as far as not breaking existing behavior, the existing test coverage suffices, but in terms of verifying that it works as advertised, for sure. I have not written any D8 tests, and wonder if you can elaborate on where this test should live, i.e., as part of an existing file that tests the ViewsJoin class in "core/modules/views/tests/" or one of it's sub-folders? Like, should I expand "./core/modules/views/tests/modules/views_test_data/src/Plugin/views/join/JoinTest.php" or add a new file?

Also, any ideas on what test cases should be used would be welcome - I have my limited need-to-use-now test cases which are built on contrib modules so I will have to make these up from scratch as it were. Thanks again!

lendude’s picture

I am guessing that as far as not breaking existing behavior, the existing test coverage suffices

We can but hope :) But it comes back green, so lets assume it doesn't break anything (and if it does, we just uncovered a hole in our test coverage).

Adding coverage to \Drupal\Tests\views\Kernel\Plugin\JoinTest sounds like a perfect place to start. Either just add to testBasePlugin() or if you feel there is too much other test config in the way from previous assertions, add a new test method and start from there. Add tests for different operators and see what happens.

Also we need to make really sure to run the tests on all supported databases (just queue some more tests after you upload a patch), because edge case stuff like this tends to break across different databases. I tried some other operators then = on Postgres and that seemed fine, but we have to be sure.

robertwb’s picture

Thanks for the feedback @LenDude - I will proceed.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

aerozeppelin’s picture

Status: Needs work » Needs review
StatusFileSize
new2.34 KB
new1.65 KB

Updates to patch as per#6.

lendude’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests

Tests are inline with existing coverage for these settings and look good.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
+++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
@@ -269,7 +269,8 @@ public function buildJoin($select_query, $table, $view_query) {
-    $condition = "$left_field = $table[alias].$this->field";
+    $operator = !empty($this->configuration['operator']) ? $this->configuration['operator'] : '=';
+    $condition = "$left_field $operator $table[alias].$this->field";

Should we be worried about existing views with operators other than = now behaving very differently? I.e. do we need an upgrade path to change any operators to = so as to not have a behaviour change?

robertwb’s picture

I suppose that IS a worry. But, the only problem with forcing all to '=' upon update *should* only break installs that have previously applied this patch, however, there may be other sub-classes of the views_join class that do NOT suffer from this bug. If that were the case then forcing to '=' could be really problematic.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

bwong’s picture

Could this be expanded to support the 'formula' operator that can be used in SQL conditions? This would be useful in referencing different tables to the left of the join. Right now I have to use 'formul' in a WHERE condition which is less efficient.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev
quietone’s picture

Version: 9.3.x-dev » 9.4.x-dev
StatusFileSize
new2.33 KB
new2.33 KB

Reroll

quietone’s picture

Issue summary: View changes
Issue tags: +Bug Smash Initiative
lendude’s picture

Status: Needs review » Needs work

Re #11 : As far as I can tell, this configuration would come from ViewsData and not Views config, so not sure how we could do an upgrade path for that. But might be missing something.

But it might be worth it to add a CR that if somebody had defined an 'operator', it will now actually get used.

+++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
@@ -310,7 +310,8 @@ public function buildJoin($select_query, $table, $view_query) {
+    $operator = !empty($this->configuration['operator']) ? $this->configuration['operator'] : '=';

Instead of falling back to a default here, wouldn't it be better to set this in the constructor where we are already setting some default values? That way we keep the default settings together.
So add it to this:

    // Merge in some default values.
    $configuration += [
      'type' => 'LEFT',
      'extra_operator' => 'AND',
    ];
quietone’s picture

Status: Needs work » Needs review
StatusFileSize
new1.06 KB
new2.59 KB

#23. Updated the patch as requested.

Added a CR but needs instructions for what action to take, which I am not sure about.

Should a new example be added in JoinPluginBase?

lendude’s picture

Status: Needs review » Needs work
+++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
@@ -258,6 +258,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
     $configuration += [
...
+      'operator' => !empty($this->configuration['operator']) ? $this->configuration['operator'] : '=',

This doesn't need the ? because it is getting added with +=, which in effect already does the empty check. So less logic needed, which is good I think :)

lendude’s picture

CR looks great, added a short line about the possible steps you need to take to update your code.

quietone’s picture

Status: Needs work » Needs review
StatusFileSize
new708 bytes
new2.55 KB

#25. Yes, of course. Should be fixed in this patch,

Glad you liked the CR.

larowlan’s picture

Status: Needs review » Needs work

But it might be worth it to add a CR that if somebody had defined an 'operator', it will now actually get used.

Yes this is my first thought too. We've had broken code for a long time, that might suddenly start working and cause an unintended consequence.

For that I think we should add a CR.

quietone’s picture

Status: Needs work » Needs review

@larowlan, do you mean the existing CR needs more information?

larowlan’s picture

Sorry, I missed that there was already a change notice

lendude’s picture

Status: Needs review » Needs work
+++ b/core/modules/views/src/Plugin/views/join/JoinPluginBase.php
@@ -258,6 +258,7 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
+      'operator' => $this->configuration['operator'] ?? '=',

We don't even need the ??, it can just be

'operator' => '=',

right?

quietone’s picture

Status: Needs work » Needs review
StatusFileSize
new630 bytes
new2.52 KB

@Lendude, sorry to keep taking your time.

lendude’s picture

Status: Needs review » Reviewed & tested by the community

Thanks for taking the time to keep coming back to this :)

Nothing to add from me anymore, looks ready.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed 1760fab770 to 10.0.x and 2ce5ee3db5 to 9.4.x. Thanks!

Given the CR only merged back to 9.4.x

  • alexpott committed 1760fab on 10.0.x
    Issue #2845571 by quietone, aerozeppelin, robertwb, Lendude: ViewsJoin...

  • alexpott committed 2ce5ee3 on 9.4.x
    Issue #2845571 by quietone, aerozeppelin, robertwb, Lendude: ViewsJoin...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.