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.
| Comment | File | Size | Author |
|---|---|---|---|
| #13 | flag-postgresql_views_relationship_error-2929733-13.patch | 634 bytes | dewalt |
Issue fork flag-2929733
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
Comment #2
tr commentedThat 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.
Comment #3
kaanklky commentedI 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;
Comment #4
kaanklky commentedComment #5
tr commentedThe 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.
Comment #6
taggartj commentedhad to do some thing like ...
Comment #7
eglawThe solution here:
#2864440: PostgreSQL problems on entity_id of type varchar with flagging and flag_count tables
My comment #12 has the patch included
Comment #8
eglaw[duplicate] removed
Comment #9
jcandan commentedI completely agree with #5, and have submitted a patch to core to address this.
Comment #10
izus commentedhi,
#6 made it for me, thanks @taggartj
Comment #11
luisnicg commentedI 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.
Comment #12
liam morlandThis seems to be a duplicate of #2864440: PostgreSQL problems on entity_id of type varchar with flagging and flag_count tables.
I had this problem and was able to solve it with in the patch in #3079534-27: Views JOIN condition fails in PostgreSQL when comparing entity identifiers of different datatypes.
Comment #13
dewalt commentedPatch #3079534 works, but there is also ability to do the same with internal module changes. Please test the patch.
Comment #14
ivnishNeeds reroll to MR
Comment #15
deaom commentedIf 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.
Comment #16
orkutmuratyilmaz@deaom, according to #13, it is still kind of a Flag issue too, as far as I understand.
Comment #18
liam morlandI have made a merge request with the patch in #13.
Comment #19
benstallings commentedClaude 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.
Comment #20
liam morlandTests are failing.
At the time that comment #19 was posted, the merge request also needed to be rebased. Claude gets it wrong again.
Comment #21
benstallings commentedComment #22
benstallings commentedComment #23
orkutmuratyilmaz@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:)