mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
Cannot safely type bigint column as int when used with dbal 3.x
#7442
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @acoulton on GitHub (Nov 22, 2024).
Bug Report
Summary
When using any version of ORM with DBAL 3.x, an entity with a column type
bigintand a property typeintis incorrectly treated as changed every time it is used. This causes high volumes of unexpected database writes (and listener invocations).Prior to 2.19.4,
orm:validate-schemawould report that the column type and property type were incompatible. That was changed in #11414 to fix #11377 - as a result doctrine no longer warns about this issue.I reported this at the time, but I think as we were discussing on a closed PR (and I didn't get a chance to follow up) it has been overlooked.
Current behavior
Given an entity like:
When I run
doctrine orm:validate-schemathe schema validates successfully.If I then run code like:
And examine the queries from my database logs, I can see two queries:
SELECT FROM my_entity WHERE id = 1UPDATE my_entity SET number = 20 WHERE id = 1.This happens because:
bigintis hydrated as a string{original value returned by dbal} === {current value of entity property}- that link is for 2.x, but the logic is the same in 3.x and 4.xintthen PHP has automatically typecast'15'to15when hydrating the object.'15' === 15, this does not match, so the entity is added to the changeset and marked for update.Expected behavior
Either:
How to reproduce
I have not created a failing test because the correct test depends on how you would prefer to solve this.
I believe that the reproduction is clear from the description and links to how the implementations cause this bug, but am happy to create an official reproduction if it would help.
Proposed fix
IMHO the best solution is probably to fix this directly in the UnitOfWork, to allow people to type properties correctly and eliminate the unnecessary writes.
The
===comparison appears in bothcomputeChangeSetandrecomputeSingleEntityChangeSet.I would suggest therefore extracting a method something like:
If this is acceptable I can work on a PR with implementation and tests.
@andrei-dascalu commented on GitHub (Feb 3, 2025):
I like the idea that the validation should warn about this.
Sure, the issue with using int for db type bigint only manifests itself for very large unsigned values but it's better to just prevent the issue altogether rather than magically casting behind the scenes to bypass type issues.
You can ignore it for as long as you can in the check but assuming you're using bigint for a reason, you're going to have issues eventually.
@acoulton commented on GitHub (Feb 7, 2025):
To be fair, generally speaking on 64 bit systems, it is generally safe to use
BIGINT- the min/max for a signed bigint is (as far as I know on all database platforms) the same as PHP_INT_MIN / PHP_INT_MAX.It's only risky if you're using
BIGINT UNSIGNED. Hence why I think dbal decided to provide it as an int whenever they could, as in the vast majority of modern cases that will work as expected.Therefore my preferred solution would be to allow usage as an
intbut fix the currently broken persistence behaviour.If validation is reintroduced, it should maybe only be if you have an
intproperty but the column is unsigned and/or your PHP_INT_(MIN/MAX) don't match theBIGINT UNSIGNEDrange (e.g. if you're on a 32 bit system).