Problem/Motivation

Entity IDs can be either a string or an int. Both are acceptable, and even tested for (EntityTestStringID.php). Postgres cannot join across different datatypes. So, when a View lists a relationship between two tables, and the shared identifier stores one as a string and the other as an integer, the query causes an error:

SQLSTATE[42883]: Undefined function: 7 ERROR: operator does not exist: bigint = character varying

Proposed resolution

Cast both condition values to strings.

Issue fork drupal-3079534

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

jcandan created an issue. See original summary.

jcandan’s picture

StatusFileSize
new626 bytes

This fix casts the left and right join condition values as TEXT.

> Note: I personally think that the condition statement modified in this patch should go through pgsql driver, and it be cast there. But I was not sure what the best implementation would be.

jcandan’s picture

Version: 8.7.7 » 8.7.x-dev

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

Drupal 8.7.9 was released on November 6 and is the final full bugfix release for the Drupal 8.7.x series. Drupal 8.7.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.8.0 on December 4, 2019. (Drupal 8.8.0-beta1 is available for testing.)

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.

davidferlay’s picture

Faced that issue, this patch seems to solve it entirely when using PostgreSQL

But it breaks site when patch is used with MySQL, meaning codebase is coupled with infra, which is not cool and should be avoided

davidferlay’s picture

Status: Active » Needs review
andypost’s picture

davidferlay’s picture

Status: Needs review » Needs work

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
jakegibs617’s picture

I did see initial success using the patch from #2 but later I saw very steep costs to performance due to this. This is applied to all views which can be dangerous. And it caused one of my views which originally might take up to 7 seconds to load to result in over 15 minutes to load.

Without the patch: Execution Time: 2214.311 ms, cost=52932.30
With the patch and a functional index: Execution Time: 7849.606 ms but the cost=220466848333415508344832.00 (way to big)

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mr_scumbag’s picture

StatusFileSize
new704 bytes

Updated this patch for Drupal 9.4.1

priya.chat’s picture

Status: Needs work » Needs review
StatusFileSize
new702 bytes

Hi All, Updated the patch #14 with few minor changes.

Status: Needs review » Needs work

The last submitted patch, 15: psql-views-join-id-3079534-15.patch, failed testing. View results

priya.chat’s picture

Status: Needs work » Needs review
StatusFileSize
new686 bytes

Tried to the syntax error by corrected the cast operator as getting syntax error in the previous patch.

Status: Needs review » Needs work

The last submitted patch, 17: psql-views-join-id-3079534-17.patch, failed testing. View results

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

prhuang’s picture

StatusFileSize
new719 bytes

Added a CAST as CHAR to solve the issue.

joel_osc’s picture

Status: Needs work » Needs review
prhuang’s picture

StatusFileSize
new702 bytes

Removed the trailing spaces.

Status: Needs review » Needs work

The last submitted patch, 22: 3079534-21_psql-views-join-id.patch, failed testing. View results

luisnicg’s picture

Complementing #12
In addition to performance issues, I got duplicated rows in different views, for example, I got duplicated results after filtering users by mail in /admin/people.

I would recommend validating the database type before doing the CAST, since this only happens with "pgsql", then validate the type of the field (if entity type exists) and validate if the field doesn't have "id" as sub-string (assuming all ids are INT)

I solve my specific issue with this https://www.drupal.org/project/flag/issues/2929733#comment-12836956

luisnicg’s picture

StatusFileSize
new1.05 KB

Based on my previous comment I've created this patch.

luisnicg’s picture

StatusFileSize
new1.05 KB

I have placed strrpos params wrong, patch was updated.

xdequinze’s picture

StatusFileSize
new966 bytes

The last patch didn't work for me, using Drupal 9.5.11.
I updated to make it working.

liam morland’s picture

Version: 9.5.x-dev » 11.x-dev
Status: Needs work » Needs review

The patch in #27 fixes this for me in Drupal 10.2. It also applies to Drupal 11.

liam morland’s picture

StatusFileSize
new935 bytes

This improved patch casts to text instead of bigint. This fixes additional failures I was having.

I have created a merge request with the patches in 27 and 29.

liam morland’s picture

I have updated the tests so that they pass with the changes.

joseph.olstad’s picture

@Liam Morland, while the tests are passing on the merge request, it's not apparent which database system is being tested. It would be good to just make sure that MariaDB/Mysql/Sqlite are also passing and also all versions of PostgreSQL. With the MR test, it wasn't obvious which setup was being tested (maybe I'm missing something?).

liam morland’s picture

I have run the tests on all the platforms available in the pipelines. They have all passed. If you click on the pipeline number in the MR, you can see the full results.

lendude’s picture

Can we use \Drupal\views\Plugin\views\join\CastedIntFieldJoin for this and avoid adding pgsql specific code to base plugins?

liam morland’s picture

It looks like it will be deprecated: #3376464: [PP-1] Deprecate and remove Drupal\views\Plugin\views\join\CastedIntFieldJoin.

By its name, it sounds like it would cast to int. The merge request has it casting to text because entity identifiers are not always integers.

liam morland’s picture

Current changes without the test updates.

smustgrave’s picture

Hiding patches for clarity.

Leaving in NR as seems desire is/was to move pgsql specific code out of base

liam morland’s picture

Where would you suggest this code be put?

joseph.olstad’s picture

@smustgrave , the suggested approach to move pgsql specific code out of base is marked to be deprecated.
see comment #35
#3079534-35: Views JOIN condition fails in PostgreSQL when comparing entity identifiers of different datatypes

lendude’s picture

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

Well if there is a use for it, we can always undeprecate it (or in this case, never deprecate it in the first place), or if it needs a string version of this we should add a string version and put it in the pgsql module where this seems to belong (is PostgreSQL the exception here or is MySQL? How does SQLite handle this?)

Also, I think the general consensus is that int joins are more performant than string joins, so what performance impact does casting everything to a string have? We should check.

How is this handled outside Views? It's not like Views is the only place you can make joins. Is there maybe some method we could/should add to the database drivers that handles this?

I would like to see test coverage added that actually shows we need this, so something that would fail without this fix. All the modified test coverage changes only show that the ':text' is added and this doesn't break existing queries.

liam morland’s picture

At the moment, Postgres is the exception, though I think that it is doing it more correct under the SQL standard. I don't know what SQLite does.

I ran into this problem as described in #2864440: PostgreSQL problems on entity_id of type varchar with flagging and flag_count tables. Other related issues describe how this has surfaced.

The problem is that id columns can be either string or integer. If there is a way to of knowing which it is then it could use integer casting when that is possible.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

orkutmuratyilmaz’s picture

I've tried different patches and the Merge Requests (as patches) on a D11.3.3, PG17 installation. Unfortunately, none of them worked. Do I miss something?

liam morland’s picture

joseph.olstad’s picture

Status: Needs work » Reviewed & tested by the community

This change is reasonable IMHO and the tests have been adjusted. Client of mine is migrating from MySQL to pgsql for several reasons and we'll appreciate this improvement.

Would be good if this fix made it into 11.4.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

This solution around str_contains($this->field, 'id') does not feel correct. Firstly it can produce both false positives and false negatives. For example the uuid field or any field containing the string id. Also, casting an indexed integer column to ::text in a JOIN … ON condition makes PostgreSQL unable to use the index on that column. For large tables (e.g., node_field_data, users_field_data) this could turn an index seek into a full table scan.

We need to compare the columns and only add ::text cast to the necessary column. However we don't have an API to introspect the table schema so we'll need to add one. Ideally we should file fixes in modules that cause this problem - ie. in the flagging case we should add an integer column to the table flagging_count table in in the case where we join to an entity with an integer ID we should join to that column.