Problem/Motivation

The /bookmarks page showing error "The website encountered an unexpected error. Please try again later." when try to list user's own bookmarks list.

[error] 12722#0: *1860 FastCGI sent in stderr: "PHP message: Uncaught PHP Exception Drupal\Core\Database\DatabaseExceptionWrapper: "Exception in Flag Bookmark list[flag_bookmark]: SQLSTATE[42883]: Undefined function: 7 ERROR:  operator does not exist: bigint = character varying
LINE 6: ...g flagging_node_field_data ON node_field_data.nid = flagging...
                                                             ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.: SELECT COUNT(*) AS expression
FROM 
(SELECT 1 AS expression
FROM 
{node_field_data} node_field_data
INNER JOIN {flagging} flagging_node_field_data ON node_field_data.nid = flagging_node_field_data.entity_id AND (flagging_node_field_data.flag_id = :views_join_condition_0 AND flagging_node_field_data.uid = :views_join_condition_1)
INNER JOIN {users_field_data} users_field_data_node_field_data ON node_field_data.uid = users_field_data_node_field_data.uid
WHERE node_field_data.status = :db_condition_placeholder_0) subquery; Array
( [...]

I think the cause of exception is comparing 'bigint' with string on PostgreSQL. I tried to build same installation with MySQL 5.5 and everything works as expected.

Drupal installation is running on Drupal 8.x and PostgreSQL 9.5.

Issue fork flag-2929733

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

kaanklky created an issue. See original summary.

tr’s picture

That query seems to be created by Views. (The /bookmark page is a View, and the query is not one that appears in the Flag source code). This error is essentially the same as many others that I found in the issue queues. The one with the most information is probably #2747079: "Undefined function: 7 ERROR: operator does not exist: bigint" error with a PostgreSQL database. There's a hack in there that "fixes" this, but what it does is implement hook_views_query_alter() and put in PostgreSQL-specific code. Not a good solution, but it may be a workaround if you're desperate.

To me this feels more like a Views problem or a problem with the Drupal PostgreSQL driver. Flag's only input is to define the View via the views.view.flag_bookmark.yml file. I ran the configuration inspector and I verified that this file agrees with the schema, so what Flag passes to Views is type-correct.

kaanklky’s picture

I do not know why developer of flag module defined the entity_id as a varchar on database, it is an id field and it do not need to be string in my opinion.

So I fixed the situation with this query;

ALTER TABLE "flagging"
ALTER "entity_id" TYPE bigint USING entity_id::bigint,
ALTER "entity_id" DROP DEFAULT,
ALTER "entity_id" DROP NOT NULL;
kaanklky’s picture

Status: Active » Needs review
tr’s picture

Status: Needs review » Active
Issue tags: -Flag

The Flag module uses the core Drupal Entity API, and Drupal explicitly allows entity IDs to be either integers or strings. There's even a set of core tests written to make sure, among other things, that the code runs correctly if you use string IDs (core/modules/system/tests/modules/entity_test).

This is why I'm saying the problem and the needed fix isn't in the Flag module:
1) Many other modules experience the same problem, and the problem shows up in queries generated by Views - check google.
2) The Entity API declares that an entity ID may be either a string or an int, so Flag is allowed to use the string type for the flagged entity ID. In fact, because entity_id is used to hold the ID of the flagged entity, it *should* be a string - that allows for flagged entities to have either int or string IDs.

One way to address this is to alter your own table or change the Flag module, but that doesn't help anybody but you and it just pushes to the problem to another spot - you will now not be able to Flag entities with a string ID.

The first thing I would do is look at Views and see if there's some way to change the way Views builds that query so that it casts the JOIN id's to the same type to prevent the PostgreSQL error. But seeing the hook_views_query_alter() that I linked to above, that probably has to be done at the PostgreSQL driver level (core/lib/Drupal/Core/Database/Driver/pgsql). If you can develop a fix, that should be addressed in the core Drupal issue queue. In fact if you search you might even find an existing issue for this in the core queue.

Changing the status back to Active. Needs Review is for when you have provided a patch that needs to be reviewed. There's no patch here. A patch to change the BaseFieldDefinition type would also have to provide an update function so that existing sites could update to the new definition, as well as provide an update test to make sure the update works properly. But as I said, then you would be just avoiding this one problem and causing another.

taggartj’s picture

had to do some thing like ...

use Drupal\Core\Database\Database;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;

/**
 * Implements hook_views_query_alter()
 */
function MYMODYLE_user_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  $db = Database::getConnection()->driver();
  if ($db == 'pgsql') {
    if (isset($view->relationship['flag_relationship'])) {
      $query->getTableInfo('flagging_node_field_data')['join']->field .= '::bigint';
    }
  }
}

eglaw’s picture

eglaw’s picture

[duplicate] removed

jcandan’s picture

I completely agree with #5, and have submitted a patch to core to address this.

izus’s picture

hi,
#6 made it for me, thanks @taggartj

luisnicg’s picture

I got the same error with group and webform modules when you assign one of the element to the form as a group entity.
#6 works for me.
I also applied #9, the one that was posted for the core, but I got duplicated rows in different views, for example, I got duplicated results after filtering users by mail in /admin/people.

liam morland’s picture

dewalt’s picture

Status: Active » Needs review
StatusFileSize
new634 bytes

Patch #3079534 works, but there is also ability to do the same with internal module changes. Please test the patch.

ivnish’s picture

Version: 8.x-4.0-alpha2 » 5.x-dev
Status: Needs review » Needs work
Issue tags: +Needs reroll

Needs reroll to MR

deaom’s picture

If this is a Views problem and patch from Views solves the issue (it will be committed at one point) the patch can be added via composer, why would you then want to solve the same issue within the contributed module?
I think this issue is not a Flag issue and therefore the issue can be closed.

orkutmuratyilmaz’s picture

@deaom, according to #13, it is still kind of a Flag issue too, as far as I understand.

liam morland’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll

I have made a merge request with the patch in #13.

benstallings’s picture

Status: Needs review » Reviewed & tested by the community

Claude Code says:

Overview

Fixes a long-standing PostgreSQL compatibility bug in the Flag Views relationship. flagging.entity_id is defined as a string (varchar) in Flagging.php:126, but many entity ID columns (e.g., node.nid) are integers. MySQL silently coerces the types during JOIN, but PostgreSQL raises a type-mismatch error. The fix sets a left_formula on the relationship that casts the base-table's ID column to varchar, producing a JOIN condition like CAST(node_field_data.nid AS varchar) = flagging.entity_id.

Correctness

- Approach is sound. Using Views' left_formula is the standard way to override the left side of a relationship JOIN, and CAST(x AS varchar) is portable across MySQL, PostgreSQL, and SQLite.
- ensureMyTable() is required before reading $this->tableAlias — the call at line 172 is correct.
- No SQL injection risk. $this->tableAlias and $this->realField are Views-internal identifiers, not user input.
- Direction of cast is right. Casting the numeric base ID → varchar avoids CAST('abc' AS int) failures when flagging non-numeric entities (e.g., config entities keyed by string IDs).

Suggestions

- Unconditional cast has a perf cost. CAST(base.id AS varchar) on the left side of a JOIN prevents PostgreSQL from using an index on the base table's ID column. For views that return from large entity tables this can degrade noticeably. Consider casting the right side instead — flagging.entity_id is already varchar, so no cast is needed there — or only apply the formula when the base column type is non-string. A cheaper alternative would be to cast the flagging side once (e.g. CAST(flagging.entity_id AS int)) only when the base entity's ID column is integer, which preserves index use on the larger base table.
- Placement. The mutation happens inside query() before parent::query() at line 211, which is the correct hook. Leaving it as-is is fine.
- No test added. The module has a tests/ directory but this PR ships no regression test. A kernel or functional test exercising FlagViewsRelationship::query() against a node view would catch reintroductions — though PostgreSQL-specific coverage requires a multi-DB CI matrix, so this may be a known limitation of the project's test setup.
- Minor style. CAST($this->tableAlias.$this->realField AS varchar) uses string interpolation with a dot between properties, which works but is slightly easier to misread than {$this->tableAlias}.{$this->realField}. Not a correctness issue.

Risks

- Behavior change on MySQL users. Existing queries that worked fine on MySQL now run through a CAST. MySQL's optimizer generally handles this, but if the site relied on an index on the base ID column for a large flagged view, query plans could shift. Low but non-zero risk.
- Upstream/contrib interaction. Any code that read $this->definition['left_formula'] or expected left_field to be authoritative will see the new formula. Unlikely to be an issue since this is internal to the plugin.

Verdict

Small, targeted, correct fix for a real cross-DB bug. Ship it, ideally with a follow-up to consider the index/performance trade-off and add a regression test.

liam morland’s picture

Status: Reviewed & tested by the community » Needs work

Tests are failing.

At the time that comment #19 was posted, the merge request also needed to be rebased. Claude gets it wrong again.

benstallings’s picture

Assigned: Unassigned » benstallings
benstallings’s picture

Assigned: benstallings » Unassigned
Status: Needs work » Needs review
orkutmuratyilmaz’s picture

Status: Needs review » Reviewed & tested by the community

@benstallings I've just tested your latest commits on the last MR, as a patch, and I can confirm that the bug is gone now:)