Problem/Motivation
I created a custom entity who's id field definition looks like this:
$fields['id'] = BaseFieldDefinition::create('integer')
->setLabel(t('ID'))
->setDescription(t('The ID of the thePlatform Media entity.'))
->setSettings([
'size' => 'big',
])
->setReadOnly(TRUE);
Whenever I create an entity reference field on another entity and reference it to this entity, I get this error:
The website encountered an unexpected error. Please try again later.
Drupal\Core\Entity\EntityStorageException: SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'field_video_target_id' at row 1: INSERT INTO {node__field_video} (entity_id, revision_id, bundle, delta, langcode, field_video_target_id) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5); Array ( [:db_insert_placeholder_0] => 752238 [:db_insert_placeholder_1] => 1204418 [:db_insert_placeholder_2] => video [:db_insert_placeholder_3] => 0 [:db_insert_placeholder_4] => en [:db_insert_placeholder_5] => 39742019557 ) in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 757 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).
Drupal\Core\Database\Statement->execute(Array, Array) (Line: 615)
Drupal\Core\Database\Connection->query('INSERT INTO {node__field_video} (entity_id, revision_id, bundle, delta, langcode, field_video_target_id) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5)', Array, Array) (Line: 86)
Drupal\Core\Database\Driver\mysql\Connection->query('INSERT INTO {node__field_video} (entity_id, revision_id, bundle, delta, langcode, field_video_target_id) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5)', Array, Array) (Line: 37)
Drupal\Core\Database\Driver\mysql\Insert->execute() (Line: 1265)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->saveToDedicatedTables(Object, , Array) (Line: 853)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->doSaveFieldItems(Object) (Line: 268)
Drupal\Core\Entity\ContentEntityStorageBase->doSave(NULL, Object) (Line: 397)
Drupal\Core\Entity\EntityStorageBase->save(Object) (Line: 748)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->save(Object) (Line: 363)
Drupal\Core\Entity\Entity->save() (Line: 361)
Drupal\node\NodeForm->save(Array, Object)
call_user_func_array(Array, Array) (Line: 116)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object) (Line: 56)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 588)
Drupal\Core\Form\FormBuilder->processForm('node_video_form', Array, Object) (Line: 319)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 53)
Drupal\Core\Entity\EntityFormBuilder->getForm(Object) (Line: 118)
Drupal\node\Controller\NodeController->add(Object)
call_user_func_array(Array, Array) (Line: 128)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 577)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 129)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 102)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array) (Line: 139)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 62)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 62)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 53)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 55)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 34)
Drupal\gc_api\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 637)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
It looks like the field schema always assumes the id is a standard size int rather than a big int. :(
Proposed resolution
Get the size of the field from the field definition and set it to the same.
Remaining tasks
Write PatchMake tests
User interface changes
None.
API changes
Allows entity reference to reference other entities that have a big int id.
Without that patch - this feature is simply not working, showing the fatal error. So we don't need any upgrade paths or migrations, we are only making this feature work as expected. This consensus was reached on Drupal Slack with @catch.
Data model changes
This patch simply fixes the entity reference table's target_id
to be a big int.
Comment | File | Size | Author |
---|---|---|---|
#82 | 2680571-nr-bot.txt | 149 bytes | needs-review-queue-bot |
#73 | core-bigint_entity_reference-2680571-73-only-failing-test.patch | 3.35 KB | Murz |
Issue fork drupal-2680571
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
davidwbarratt CreditAttribution: davidwbarratt at Golf Channel commentedComment #3
davidwbarratt CreditAttribution: davidwbarratt at Golf Channel commentedComment #4
davidwbarratt CreditAttribution: davidwbarratt at Golf Channel commentedComment #6
davidwbarratt CreditAttribution: davidwbarratt at Golf Channel commentedComment #7
davidwbarratt CreditAttribution: davidwbarratt at Golf Channel commentedComment #8
tstoecklerWow, this a pretty nice find.
Thinking about this some more I wondered whether we couldn't just use a copy of* the actual id field definition and override the label. But there is no method for doing that, and even if there were - despite sounding nice at first - it might actually be a can of worms, not sure. So scratch that.
Then I thought: at least we could take over all settings of the ID field, i.e.
$target_id_definition->setSettings($id_definition->getSettings())
. That would also catch the unsigned setting which we currently just assume exists for the id field. But again, I'm not really sure, what all else this would entail and if that isn't really a can of worms. And this particular piece of code is pretty awful anyway with the explicit data type checking, so I think there is actually value in being explicit....so I think this is really good to go. Could use another pair of eyes, though, so not setting RTBC.
* I'm intentionally not using the word "clone" here, because cloning in typed data land is a rabbit hole I'm neither intellectually capable nor emotionally stable enough to go down...
Comment #9
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedLooks great to me!
Comment #10
davidwbarratt CreditAttribution: davidwbarratt at Golf Channel commentedThere's also an assumption in the migration map tables #2681055: Migrate destination assumes the ids are 'normal' size when they could be 'big'.
Comment #11
catchSeems worth adding test coverage for.
Since it looks like it's not possible to actually have a working reference field at the moment that suffers from this bug, I don't think we need an upgrade path - but would be good to double check this.
Comment #12
tstoecklerWould you be content with unit test coverage or do you think integration test coverage is necessary here?
Comment #13
catchUnit test coverage might be OK. However I'm rethinking not needing an upgrade path here due to this hunk:
Wouldn't the state entry be out of sync anyway in this case?
Comment #14
davidwbarratt CreditAttribution: davidwbarratt at Golf Channel commentedWe technically do need an upgrade path, if you have an entity with a big int, and then you create an entity reference field to that entity, it will get a size of normal, which is fine, until you get to an int that is larger than 11. When that happens, you wont be able to save the reference. :(
I added the comment, because with
normal
Drupal thought all of them needed to be updated, not just the ones that arebig
Comment #16
effulgentsia CreditAttribution: effulgentsia at Acquia commented@catch, @alexpott, @xjm, @Berdir, @swentel, @plach, and I discussed this issue and agree with it being Major priority, per https://www.drupal.org/core/issue-priority#major-bug: "a PHP error triggered under rare circumstances or affecting only a small percentage of all users".
Comment #17
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedWrote some tests for the bug, an upgrade path and a test for the upgrade path.
Comment #18
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedNote that the new patch adds the 'size' setting to the schema unconditionally, because I think it's easier to maintain the code like that :)
Comment #21
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedFixed that.
Comment #22
R.Muilwijk CreditAttribution: R.Muilwijk at Trinoco commentedThis fixes the target_id problem when setting a entity id field to big int. However the entity_id fields in the tables created for fields do not follow the big int setting.
Comment #27
estoyausenteI don't know if my error is related with this case or I have to create another issue to explain it (let me know if you think that I have to create another issue).
The problem is related with a "big" entity id, like this:
The problem ocours when I try to change the entity removing another field and perform an entity-update. To remove a field Drupal create an auxiliar table "field_deleted_data_" and This table is thrown me an error related with the id size.
This is the error:
I think that the problem is strongly related with the main case because is an unhandled situation caused for a big integer id.
EDIT: searching again in the issue queue, I found this: https://www.drupal.org/project/drupal/issues/2889619 mybe related with the issue too.
Comment #28
hchonov@estoyausente, yes your problem is related to the current issue.
We need to add the int size also to the
$id_schema
in\Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::getDedicatedTableSchema()
, which is used for theentity_id
column of dedicated field tables. To test this case we'll need to add a field with a dedicated table to the new entity type "entity_test_big_integer_id" - note that this should be a normal field, not an entity reference field as entries of normal fields with dedicated tables reference the entity they belong to through the "entity_id" column.Comment #29
estoyausenteOk and thanks @hchonov, I found a little solution not tested yet (only tested in my use case) adding something like this:
I found a problem related with the default integer size. By default integer doesn't have any size and if you set the $id_schema size as a 'normal' (the default value) all entities will be updated. I think that is better only set the 'size' property when the value is different than the default value as, for example in my case, big. (See patch attached)
Has my code sense? If the code is enough to resolve the problem (as it seems) I can try to create the test (although I never did a test like this before).
Thanks for helping.
Comment #30
hchonovYou could simply exchange this line by
in which case we'll set the size only if it has been explicitly set on the ID field definition.
@estoyausente, would you please post the full patch so that we are sure that all the tests pass.
For the additional test you could add a base field to
EntityTestBigIntegerId::baseFieldDefinitions()
with cardinality bigger than1
, which is a multiple values field and as such needs a dedicated table:Comment #31
hchonovFor the additional test to be complete we need to provide here a value for the field with a dedicated table:
Comment #32
estoyausenteIt was exactly my first approach but when I performed the entity-update, with this code all entities were updated. `$id_definition->getSetting('size')` return 'normal' as a default value although the value doesn't be set explicitly. It's a little bit difficult to find the reason because for a reason that I don't know my breakpoints were ignored when I set it inside this function and I cannot debug properly.
Anyway, I will create the full patch and try to create the test.
It's a great idea. I will try to do it.
Thanks!
Comment #33
hchonovI took a deeper look into that and the default value for the size setting comes from
\Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem::defaultStorageSettings
().This means that your change makes sense, otherwise we would need an update path and I think we actually could skip it by only setting sizes different than the "normal" one. Could you only please perform a strict string comparison?
Comment #34
estoyausente- Rerolled the code of #21 for the las 8.5 Drupal version (I'm not sure which version have to use in this case, I follow the version noted in the issue, 8.5.x-dev)
- Added my code from #29
- Added a strict string comparision
- Still need tests, I will try to develope it tomorrow.
Comment #35
hchonovWe work with the 8.6.x branch until the 8.6.0 release. If needed the patch might be backported and committed to the current release branch.
When you name your patch please append the comment number -
[issue-number]-[comment-number].patch
.It is useful to provide an interdiff between the patch you're uploading and the one on top of which you've made modifications. The naming convention for this is -
interdiff-[comment-number-first]-[comment-number-second].txt
.Comment #37
estoyausenteHi again!
I just added the test to the case, now the bug seems resolved.
Edit: the patch applied correctly in 8.7.x too.
Comment #39
estoyausenteI tried to check why the patch fail the test, I think that my code fail in `Testing Drupal\Tests\Core\Entity\Sql\SqlContentEntityStorageSchemaTest`because I restested the code of #29 and it throw 1 fail but the other error are related with the entity reference changes but I don't know exactly why.
Any idea or help to find the correct path to resolve it?
Comment #40
hchonovLooking at the test fails we see that now a size of "null" is being added and it is because we don't check here if the size setting is present at all. The condition here has to be
if ($size && ($size !== 'normal'))
.Thinking over the patch again I think that it will be better if we are consistent and always set the size if present. In this case we'll have to provide an update for that change.
This update has to be moved to the system module, as the field module isn't required, which means that in some special installations the update might not run.
Comment #41
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedI was thinking about this problem lately and @tstoeckler was right in #8, that's exactly what we should do. And it's not really a can of worms either :)
Here's a mostly re-written patch.
Comment #47
MurzSeems patch works well for common cases, but why it fails so much automated test (24,828 pass, 53 fail)? Maybe those test must be updated too for support current changes?
Comment #48
MurzSeems the main reason of test fails is missing upgrade scripts for SQL schemas of some already created entities, example:
The SQL storage cannot change the schema for an existing field (content_translation_uid in entity_test_update entity) with data.
So, maybe easier will be don't touch SQL schemas of already exists fields, but allow
big int
only for newly created entity reference fields? And provide manually upgrade functions for needed fields.Comment #49
KapilV CreditAttribution: KapilV as a volunteer and at Innoraft for Drupal Care, Drupal Association commentedComment #50
KapilV CreditAttribution: KapilV as a volunteer and at Innoraft for Drupal Care, Drupal Association commentedhear a reroll.
Comment #51
MurzIn patch at #50 there is:
this function is already exists in module, as result we got an error on update.php:
so we must bump it to something like
system_update_8902()
?Comment #52
MurzInteresting, that on Drupal 8.9.6 I successfully create a new entity reference field to entity, that have bigint id field (via bigint contrib module), and all works well without this (or any other related) patch! The issue is only that
field_entityreferencefield_target_id
have 'varchar(255)' format instead of 'int'.Comment #53
MurzSo, maybe create a less massive patch (maybe as alternative to current), that will fix only this problem, and don't touch id's of all other entities via hook_update_N()?
Comment #54
MurzHere is simplified patch, that change field schema only for fields, that have size, differ from default ("normal").
Comment #55
MurzSorry, in previous patch I forgot to cleanup debug code, here is cleaned patch.
Comment #56
andypostComment #58
MurzSeems there are also problem with deleting
entity_reference
fields with bigint, because creatingfield_deleted_data_xxxxxx
tables on field deletion action produce SQL errors. I will try to investigate this later, or maybe anyone else can do this?Comment #60
MurzI have added failing test with bigint id, and moved my implementation to branch https://git.drupalcode.org/issue/drupal-2680571/-/tree/2680571-bigint-re...
Comment #61
MurzComment #62
MurzComment #63
Nikitoring CreditAttribution: Nikitoring at Digiterra commentedYeah! It's works.
Comment #66
MurzMR applies and works well on Drupal 9.3.x-dev branch, and tests are passed too. What other steps do we need to commit this feature?
Comment #67
MurzComment #68
MurzI've rebased my issue fork from Drupal 9.2.x to Drupal 9.3.x branch, what other steps we need to continue fixing this issue?
Comment #69
andypostLet's get green CI run, as it's a bug it needs test-only patch to proove that test fails without fix
I also wonder how it will affect 32-bit users (I know few still exists yet)
PS: patches are hidden as there's MR
Comment #70
MurzIf 32-bit users are not using bigint base fields, those changes must not change anything for them, but if they use - they already have a problem even without this patch ;)
Comment #71
Wim LeersI think this is an important and too long overlooked issue 🤓🙈
Comment #72
mradcliffeI added a note in the Api changes section that the consensus for not doing an upgrade path was based on discussion in Drupal Slack
Comment #73
MurzHere is patch file with only test the bigint reference field, that fails on original Drupal without fixes from this issue.
Comment #74
Wim Leers🥳 Thanks for the test-only patch, @Murz!
Comment #76
catchMoving back to needs review for the MR. (had to stop myself writing NR for the MR)
Comment #77
MurzTo reduce anxiety I also implemented migration from mismatched entity reference columns to make column size match target entity id field size, please review.
Also I'm not sure is there a right place to put this migration, or anybody can recommend some better place for it?
Comment #78
MurzI've published my OSM Localities module, that requires BigInt entity id
support in reference fields, to show how this feature is used in contrib modules.
Comment #82
needs-review-queue-bot CreditAttribution: needs-review-queue-bot as a volunteer commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #84
SocialNicheGuru CreditAttribution: SocialNicheGuru commentedI added this to my test install that has commerce 2.38 enabled.
Then I got an error:
Could not load the "commerce_order_item" order item type. in Drupal\commerce_order\Entity\OrderItem::bundleFieldDefinitions() (line 509 of /var/www/drupal10.2/html/modules/contrib/commerce/modules/order/src/Entity/OrderItem.php)
And the drush updatedb could not be run because of the error.