Problem/Motivation
MySQL by default does not allow row with an auto-increment value to insert the value zero. Therefor the users table cannot use an auto-increment value as we have the anonymous user which has the Id is zero.
Proposed resolution
Use the SQL mode NO_AUTO_VALUE_ON_ZERO when inserting the anonymous user into the user table , which allows a field with an auto-increment value to have the value zero. Then we can change the uid field for the users table to a serial type.
Remaining tasks
TBD
User interface changes
None
API changes
None
Data model changes
The uid field from the users table has been changed from an integer type without an auto-increment value to a serial type which has an auto-increment value. Almost all other entity types have a serial field for the primary key field.
Release notes snippet
The users table will be updated to change the uid column to a true serial field. See <a href="https://www.drupal.org/node/3221993">the change record</a> for more information.
Original issue summary
We should really set NO_AUTO_VALUE_ON_ZERO by default for MySQL, so that we can stop working around MySQL sillyness with 0 in auto-increment columns. This partly blocking #838438: Test the upgrade path because in this issue we need to import a Drupal 6 database, and even if we have a workaround, it's not satisfactory.
Comment | File | Size | Author |
---|---|---|---|
#54 | 838992-54.patch | 10.11 KB | alexpott |
#54 | 47-54-interdiff.txt | 1.26 KB | alexpott |
Comments
Comment #1
Damien Tournoud CreditAttribution: Damien Tournoud commentedStarter patch. We *know* that this will fail, this is just given as an offering for the test bot god.
Comment #3
Damien Tournoud CreditAttribution: Damien Tournoud commentedLet's just don't use the autoincrement in that table. It's not required anyway.
Comment #4
chx CreditAttribution: chx commentedWe were doing this , this one was one of the few core use cases of the new db_next_id until it got another column...
Comment #5
Crell CreditAttribution: Crell commentedI'm not against the original proposal to set the MySQL property by default, but I don't quite get why we also need to be changing the schema. Can someone explain that?
Comment #6
chx CreditAttribution: chx commentedCrell, noone can explain this. Ask the MySQL authors, perhaps?
Edit: in short if you use default, it uses the default 0 as dictated by NO_AUTO_VALUE_ON_ZERO. If you do
insert into sequences () values ();
then life is good... Let's unfurl the "I hate databases" flag.Comment #7
sun#3: 838992.patch queued for re-testing.
Comment #8
webchickHm. I don't really see a compelling reason for fixing this in D7? Am I missing something? It sounds like a nice to have, since we were able to get update tests working without it.
If we do choose to go ahead with it though, it needs an upgrade path now.
Comment #9
sunA very compelling to commit this patch is the last operation performed in http://api.drupal.org/api/function/system_status/7
More insightful details may be read in #204411: Anonymous user id breaks on MySQL export/import (xID of Zero get's auto-incremented on external xSQL events) (which also explains the WTF of the uid - uid value assignment that happens there).
Actually, I'm not sure why that (and corresponding hiccups in user.install) is not removed in this patch...?
Comment #10
Damien Tournoud CreditAttribution: Damien Tournoud commentedActually, I see no reason *not* to fix this, and plenty of reasons to do so: one big reason being that it leverages the playing field between MySQL (the primary development environment for most module authors) and the other databases that *users* will deploy more and more in Drupal 7 (remember the "User first, Developer later" philosophy?).
A zero inserted in a serial field on MySQL will be silently replaced by the next number in the sequence, while on *any other database* it will be simply inserted as zero.
Comment #11
Damien Tournoud CreditAttribution: Damien Tournoud commentedOh, and yes, we have plenty of cruft everywhere, including in the installation process and in the upgrade path tests, but I see no reason to derail this because of those.
Comment #12
sunI agree that this patch should be committed. However, as webchick already mentioned, simpletest.install needs a module update to change the schema for existing sites accordingly. Back to RTBC afterwards.
Comment #13
catchLet's try to do this in Drupal 9.
Comment #14
catchComment #15
andypostComment #16
alexpottAmusingly #2279395: The PostgreSQL backend does not handle NULL values for serial fields gracefully has resulted in other DBs behaving like MySQL for serial IDs when inserting a 0 as the ID. So we need to change that a little. I've been conservative with the change... we could gave the code from
to
but this feels risky it means that any code which is setting an ID to 0 would now really set it to 0 - I think it is better to leave this generic behaviour alone and hard-code the user zero issue since user is required entity and a very special case.
The patch attached installs and the update is successful on an existing site and user 0 still exists.
I think that this issue should deal with the user ID field because it is the whole point of setting NO_AUTO_VALUE_ON_ZERO
Comment #18
alexpottFixing the update path and testing it. \Drupal\KernelTests\Core\Database\SchemaTest::testSchemaAddFieldDefaultInitial() is going to be a PITA.
Comment #19
alexpottIt's late so I probably haven't thought of all the options but \Drupal\Core\Database\Query\InsertTrait::useDefaults() might be a significant barrier here. It really is not used much at all... in core it is tests and in contrib... http://codcontrib.hank.vps-private.net/search?text=-%3EuseDefaults%28&fi...
Comment #20
andypostAdded test needs @group to be added
Comment #21
alexpottHere's an un satisfactory solution to the useDefaults() issue... calling this with a serial column makes no sense - it's not necessary if you provided any other column...
Adding the group - we should remove that requirement - now we have no simpletest UI it's not necessary anymore. And oddly simpletest is the one proper use of useDefaults in contrib.
Comment #22
daffie CreditAttribution: daffie commentedThe patch looks good. It is failing for PostgreSQL.
These 2 changes make the test fail for PostgreSQL. Not sure how we can solve this the best way. It needs to be done this way because of https://bugs.mysql.com/bug.php?id=89225.
I do not think this is enough for PostgreSQL. It also need a sequence for the primary key to work properly.
I came to the same conclusion in my testing patch in #3215116: [IGNORE] Testing. It is a ugly solution, only I do not see a better one.
Comment #23
daffie CreditAttribution: daffie commentedThere is an issue for the sequences for PostgreSQL. See #3028706: New serial columns do not own sequences.
Comment #24
daffie CreditAttribution: daffie commentedWorking on this.
Comment #25
daffie CreditAttribution: daffie commentedUpdated the patch for PostgreSQL.
Comment #26
daffie CreditAttribution: daffie commentedThe patch from the previous comment was the correct one.
Comment #27
daffie CreditAttribution: daffie commentedAdd a CR and updated the IS.
Comment #28
daffie CreditAttribution: daffie commentedComment #29
Ghost of Drupal PastI am grateful this issue sees traction finally, thanks for the work!
I do not know whether we have a BC policy on this but I think this change is very wide. I think it'd be better to have a separate setting and even that is only necessary for new sites as existing sites already have their anonymous user. Even with the separate setting it's not impossible some contrib or in house reuse modules would break.
Maybe keep the change as is but do this in Drupal 10 only. The delay is not bad: if this goes in now, it gets released in December, if it doesn't, it releases next summer anyways. We could announce now so people relying on this can prepare and put it in D10.
What do you think?
Comment #30
daffie CreditAttribution: daffie commentedPersonally I do not see a problem, but lets ask for the opinion of a release manager for changing the default SQL mode for MySQL.
Also I do not see a problem with this being a BC break, only having some input on that from @alexpott or @catch would be great. I do not want to break an existing site.
@chx: Thank you for your reply!
Comment #31
alexpottI think we can do something a little simpler with the postgres statefulness... this only happens in the test runner when it's run the update in another process.
Comment #32
alexpottHere's another approach that means we only change the SQL mode on MySQL when inserting user 0. It limits the impact but gives us the ability to have serial user columns. So there are more queries when we insert user 0 but there are less when we insert any other user.
If we go down this path, the other thing we might want / need to do is to add the NO_AUTO_VALUE_ON_ZERO in the db dumps we make. This would copy mysqldump behaviour.
Comment #33
alexpottHere's the DbDumpCommand fix. Tested in locally on MySQL with serial uid column - works great.
Comment #36
Ghost of Drupal PastGreat approach. Maybe we need to set the mode during the mysql part of the update, too.
Comment #37
Ghost of Drupal PastComment #39
Ghost of Drupal Pasttypo.
Comment #41
Ghost of Drupal PastBahh!
Comment #42
daffie CreditAttribution: daffie commentedI think we need here a if-statement for driver is mysql.
Comment #43
alexpott#41 addresses #42 :)
Comment #44
daffie CreditAttribution: daffie commented@alexpott: No it does not. #41 fixes the change in user.install and #42 is about the change in DbDumpCommand.php.
Comment #45
alexpott@daffie - from the top of DbDumpCommand
There's a lot of MySQL specific stuff in the command already...
This change is quite a big win for reducing queries when creating a user. It's going to result in 3 less queries for inserting a user with an ID > 0. The two queries here and the query to clean up the sequences table in shutdown. We even do one less query on MYSQL when we insert user 0 as we don't do the clean up on shutdown. For all other DBs we support the savings are for user 0 too.
I think given the switch to not affect any other query other than user CRUD means that the "needs release manager review" from #30 is not necessary anymore. That said, I'm pretty sure @catch is going to review this one too.
Comment #46
catchYeah keeping things conservative in this patch seems sensible, I think we can open follow-ups to remove some of the special casing though.
Do we want a follow-up to try to change the behaviour here? Seems like a potential minefield, remember the issue that introduced this being tricky enough.
Let's definitely create a follow-up to make NO_AUTO_VALUE_ON_ZERO the default (in Drupal 10?).
If this is due to a bug in the pgsql driver can we add an @see? Also what happens if a contrib database driver needs similar handling?
Let's open an issue to point the @todo at.
Comment #47
alexpottThanks for the review @catch
Re #46.1 and #46.2 I think these need to be tackled together. Unless we unpick #46.1 then the only entity type that'll support insert a 0 ID is user. Amusingly the code introduced by #2279395: The PostgreSQL backend does not handle NULL values for serial fields gracefully has resulted in all dbs working like MYSQL without the NO_AUTO_VALUE_ON_ZERO. I'll open a follow-up that details that we need to address the SQL mode and the entity code together. Created #3222123: Allow entity types other than user to use an ID of 0 when the ID is a serial field
#46.3 Yep I'll link this to #3028706: New serial columns do not own sequences
#46.4 Created #3222121: Database connections are persistent across a container rebuild
Comment #48
alexpottUpdating issue summary for the scope of the current change which is much smaller than the original.
Comment #49
alexpottAS this really is now only about the UID field changing the issue title around.
Comment #50
daffie CreditAttribution: daffie commentedUpdated the CR.
Comment #51
daffie CreditAttribution: daffie commentedAll the changes look good to me.
All the points of @catch have been addressed.
The IS and the CR are up to date.
There is testing for the hook_update_N().
There is already a lot of testing for user Id is zero.
The requested follow-ups are created.
For me it is RTBC.
Comment #52
quietone CreditAttribution: quietone as a volunteer commentedI tested this patch with the drupal 7 migrate fixture.
I began with an existing instance of the drupal 7 fixture in a mysql database. I then manually added the anonymous user. With this patch applied I exported that database (to d7_dump.php) and then imported it into a Drupal 7 site. The anonymous user was present on the D7 site. That is wonderful. It solves the problem #2678468: Add uid 0 when importing the test fixtures, so it looks like that can be closed as a duplicate.
I then did a diff of core/modules/migrate_drupal/tests/fixtures/drupal7.php with the just exported d7_dump.php. There were completely different. I then exported the database from the d7 site and compared that file to the one I used to import. Again they were completely different. Looking at the files, it appears that the tables are exported in a random order. I think this regression was introduced in another issue but for migrate the exported dump files need to be in a consistent order. On the other hand, those fixtures are only getting 'tweaks' now. So probably nothing to do on this point.
Comment #53
longwaveShould this be 9301?
Comment #54
alexpott@longwave yep I guess so.
@quietone did you mean to un-rtbc this in #52. Cool to know this helps to fix #2678468: Add uid 0 when importing the test fixtures. I'm not sure that this has much to do with the order of the exported data in the file. Is it the user data that is all oddly ordered? Also I'm not sure that the dumper guarantees the order of the data exported.
Comment #55
quietone CreditAttribution: quietone as a volunteer commented@alexpott, I did not mean to change the status of this issue. Sorry about that.
Comment #56
daffie CreditAttribution: daffie commented@quietone: Thank you for your reply!
The renaming of the update function looks good to me.
Back to RTBC.
Comment #58
catchVery happy to see this RTBC.
There are workarounds in here, but most of them are working around workarounds we added because of the overall workaround of not using a serial column for the uid column, so the patch allows us to eventually remove all that technical debt in parallel, trying to do it in one go would get us nowhere I think.
#3028706: New serial columns do not own sequences is the main issue that's not a result of the logic we're changing, but we have postgres-specific upgrade code and testing to ensure we cover that.
Committed 139f911 and pushed to 9.3.x. Thanks!
Comment #59
andypostPublished CR