*** Note: Anyone who experiences difficulty with user logins after an update of drupal 7 core from before 7.83 to 7.83 or above should look at comment #52 and other comments following that.***
The users table contains a 'created' column but no 'modified' column. It would be useful to know when a row in the table was last modified to help with things like synchronization and auditing.
Example use case:
Say you want to export a list of all users who were either new to the system or who had changed their email address, on or after a given date (for example the date of a previous export). Without a 'modified' column, it's impossible to know if the 'mail' column has been modified since the user was created.
This means that we can't just export a list of new/updated users to an external system, but have to export ALL user records and check each one to make sure it's not a duplicate before importing to the external system. If the external system only supports CSV imports and doesn't have in-built duplicate checking, this becomes quite a pain because it requires doing an export from the external system first, and comparing the lists to remove duplicates. Even if the external system does have duplicate checking, it requires a larger upload file and unnecessary processing time.
---
It seems like it would be easy enough to add a 'modified' column and have the Drupal user module update it any time an update is made to a row in the users table.
In addition to the use case above, it could be useful for other synchronization scenarios as well.
Comments
Comment #1
Cauliflower CreditAttribution: Cauliflower commentedThe patch attached adds a 'changed' column to the user table and added also some views and token integration. I prefer the name 'changed' because other entities (eg. node) also use this name.
Comment #2
Cauliflower CreditAttribution: Cauliflower commentedComment #7
dpiDrupal 8 user entity has 'changed' field.
Changing to D7
Comment #8
heyyo CreditAttribution: heyyo commented+1
It will be great to have such information for D7 too.
Comment #9
Alex Bukach CreditAttribution: Alex Bukach commentedComment #11
Alex Bukach CreditAttribution: Alex Bukach commentedComment #12
stefan.r CreditAttribution: stefan.r commentedDrupal 8 has it as well and this seems like it could be useful, so I'm not opposed to adding this to a major D7 release (7.60/7.70)
Comment #13
vinayak nair CreditAttribution: vinayak nair at SDG Corporation commentedhi,
i encountered following error after applying patch::
PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'u.changed' in 'field list': SELECT u.uid AS uid, u.name AS name, u.status AS status, u.created AS created, u.changed AS changed, u.access AS access FROM {users} u WHERE (u.uid <> :db_condition_placeholder_0) ORDER BY u.created DESC LIMIT 50 OFFSET 0; Array ( [:db_condition_placeholder_0] => 0 ) in PagerDefault->execute() (line 79 of C:\xampp\htdocs\drupal-7\includes\pager.inc).
i can't acces my people menu now!!!
Comment #14
Alex Bukach CreditAttribution: Alex Bukach commented@vinayak nair did you run database update afte applying the patch?
Comment #15
vinayak nair CreditAttribution: vinayak nair at SDG Corporation commentedhi,
i updated my database but still the error is not gone.
i could not access my people menu!!!
Comment #16
tamarpe CreditAttribution: tamarpe commentedThanks for path, works but it doesn't work for updating exciting users.
Fixed it & some typo 'Last changed'.
Comment #18
tamarpe CreditAttribution: tamarpe commentedComment #19
tamarpe CreditAttribution: tamarpe commentedComment #20
tamarpe CreditAttribution: tamarpe commentedLatest one, path without 'www' to fix the tests
Comment #21
joseph.olstadpatch is probably ok
testbot is failing, see related issue
#2970950: D7 test runner not working since may 4th 2018 'Composer command failed'
Comment #22
joseph.olstadComment #24
joseph.olstadComment #25
MustangGB CreditAttribution: MustangGB commentedThis would be super useful, I've definitely had to hack
created
in the past to provide this functionality, a new column would be ideal.Comment #26
jollysolutionsworks fine for me RTBC
Comment #27
joseph.olstadBumping to 7.70, this didn't make it into 7.60
Comment #28
coffeduong CreditAttribution: coffeduong commentedI can't believe Drupal 7.70 release without it =.=
Comment #29
joseph.olstadComment #30
joseph.olstadRationale, D8 has this,
patch has tests
Patch rtbc over 2 years straight
Comment #31
hargobindAdding my results ... Patch from #20 applies fine to the latest 7.x branch. No problems with database update. UI on Admin > People works as expected. RTBC++
Once this gets in, we'll want to add patches to some of the most popular modules. I looked through the code for a handful of these of these top 100 modules and found the following (though I may have missed a few).
The following need the "changed" property to be added: views, entity (Entity API).
These modules don't appear to need updates: admin_views, ctools, metatag, token, views_bulk_operations, rules, i18n, variable, context, ds (Display Suite), search_api, strongarm, uuid.
Comment #32
very_random_man CreditAttribution: very_random_man commentedThis would be really handy to get in. :-)
Comment #33
very_random_man CreditAttribution: very_random_man commentedComment #34
Alex Bukach CreditAttribution: Alex Bukach commentedComment #35
ron_s CreditAttribution: ron_s commentedComment #36
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedRTBC + 1, approved
I don't think this is a risky change, it needs a change record though
Comment #37
mcdruidComment #38
joseph.olstadDraft change record here:
https://www.drupal.org/node/3250745
Comment #39
joseph.olstadFor the CR, would help to edit this page: https://api.drupal.org/api/drupal/developer%21globals.php/global/user/7.x
I don't have access to edit this page to add the details? Is this a role that someone could grant me? Access to edit api documentation?
Comment #40
mcdruid(via @longwave in slack...) looks like it's:
Thanks for the draft CR @joseph.olstad
Comment #41
mcdruidHmm, is that a real test fail with MySQL 8? Re-running to check.
Comment #43
mcdruidDoesn't look like it was a real test fail; phew.
Thanks everyone that contributed!
Comment #44
MustangGB CreditAttribution: MustangGB commentedAmazing, cheers.
Comment #45
mcdruidOh, sorry @joseph.olstad I was running through the CR's for the release on 1st Dec and created a new one for this change:
https://www.drupal.org/node/3251649
I somehow missed the draft you'd created. Apologies.
Comment #46
heddnWe should probably add a D9 issue to migrate changed column.
d6|7_user.yml
only migrates created, not changed.Comment #47
joseph.olstad@mcdruid, I'm on vacation at the moment on my android phone, feel free to scavange (pilfer/borrow/copy/paste) from the original CR https://drupal.org/node/3250745
Comment #48
mcdruidGood suggestion @heddn; I filed #3252133: Add the new D7 user->changed property to the migration system for that.
Comment #49
izmeez CreditAttribution: izmeez commentedWe have run into a problem after upgrading a site to Drupal 7.83 where the site was previously using Drupal 7.82 with patches including the patch in comment #20. On executing "drush updb" it returns "No database updates required." However, subsequent login after entering username and password fails with error:
Could this be related to a missing database update and require using an sql command to reset the schema_version?
Any thoughts on how to resolve this are appreciated. Thanks.
Comment #50
sillygwailoI was able to work around this by adding the column manually, but without an index.
First I tried what the database updates was attempting, with no luck:
Then I tried it without adding the index:
Back up your database before doing this, and make sure you use a database table prefix if your site has them. This only got my site up and running, nothing more. I don't know if I should attempt to add an index, but that didn't work as a second step:
Comment #51
sillygwailoThis may be due to my site having started as a Drupal site a long time ago, and it may have some a legacy database table structure. When I do a
SHOW CREATE TABLE users;
on my current database, this key already exists:Comment #52
mcdruidJust to be clear, it sounds like these are problems on sites that may have applied previous patches or otherwise had modified the
users
table as opposed to being a bug in the latest release. Obviously let me know if I've misunderstood.After
user_update_7020()
has run (or in a clean install of D7.83 or later) I'd expect the users table to look something like this:If the index doesn't look right (as in @sillygwailo's example) you should be able to drop and re-add it. (Be careful, take backups, the value of your investments may go down as well as up etc..):
@izmeez if you'd run an update as part of a previous patch and your schema's not correct you could tweak your system table to get the update to run (again take backups beforehand etc..) - something like:
...then run the db update.
However, I suspect that'd only go smoothly if you don't have the "changed" field and the index in the schema beforehand.
The data in that field shouldn't be too precious so if you had to drop the field and re-add it manually.. worse things happen. You've taken a backup or three already, right? That'd be something like:
..after which you'd need to manually re-add the index (as above).
Assuming you can get the schema for the users table to look like the above, you should be okay I'd hope.
Did we mention that you should take backups before performing manual SQL surgery?
Comment #53
izmeez CreditAttribution: izmeez commentedThank you @sillygwailo and @mcdruid.
Yes, to be clear there is no indication of a bug in the drupal 7.83 release.
The detailed explanation was helpful.
Yes, of course, first a database backup was done.
Then using the suggestion to check if the
user_update_7020()
had run with the SQL command:mysql> SHOW CREATE TABLE `users` \G
confirmed the field 'changed' was not present and using:
mysql> UPDATE system SET schema_version = 7019 WHERE name = 'user' AND type = 'module';
to reset the schema_version and running update worked to resolve the problem.
It would have been nice to check what the schema_version was at before resetting it but I was not able to figure out the correct sql command to do that.
Again, thanks for the help.
Comment #54
andrewfn CreditAttribution: andrewfn commentedI'm getting the same problem as #49 on all my Drupal 7 sites. The update fails and I can no longer log in to any of them.
Comment #55
hargobindIt's probable that some upgrades will run into this same issue -- i.e. the 'changed' column already exists -- either because someone has already applied a patch from this issue on their site (e.g. @izmeez and @sillygwailo), or they installed a module that does something similar.
Thank you @mcdruid for providing a manual solution. But here's a simple code change that checks
db_field_exists('users', 'changed')
anddb_index_exists('users', 'changed')
, and only adds the column or recreates the index as necessary.IMO, this code should have been part of the original commit.
Comment #56
izmeez CreditAttribution: izmeez commentedJust to be clear, even though we thought we had applied the patch before, on review it appears that the patch had not be fully applied (the update database had not run but the
schema_version
may have been incremented or corrupted), therefore there is some other reason why the update did not run in our case. We have not, as of yet, identified the underlying state of the site. Since we have that all so important backup, with some future new learning we may be able to go back and more clearly identify the state we were in. Thanks.Comment #57
mfbIf you download the Drupal 4.6.0 tarball (lol..) you can see that at that time there was a column called `changed`, as well as an index called `changed`. This column was renamed to `access` in system_update_136() which you can find in the 4.7.0 tarball. Doesn't look like the mysql index was renamed, so maybe it makes sense that folks still have a `changed` index..?
Comment #58
izmeez CreditAttribution: izmeez commented@mfb This is a Drupal 7 issue. If you look at comment #52 you will see that with the new drupal 7.83 release the user table now includes both a `changed` field and an `access` field. While the `access` field is a timestamp of last access, the `changed` field is a timestamp of when the user info was last changed (or modified), such as their email address. I am not sure how this relates to the corresponding field names in Drupal 9 but I would be surprised if they were thought to be the same and just treated as a renaming.
Comment #59
hargobindSee the child issues sidebar box for contrib modules that contain patches to support this new field. Please check them out and test if you get a chance.
Comment #60
mfb@izmeez my response was to #52; I'm saying that it looks possible that very old drupal sites - which have been upgraded for many years - could have a pre-existing `changed` index in the users table dating from Drupal 4.6 days. That said, I didn't try to reproduce the upgrades to see if my theory is true.
Comment #61
izmeez CreditAttribution: izmeez commented@mfb Thanks for the clarification, my bad. It is getting so confusing these days with the drupal change to versions of modules using numbers like 4.x and 5.x etc. I inadvertently thought you were talking about something new not something old like drupal 4.6 and 4.7 my apologies.
Comment #62
GoZ CreditAttribution: GoZ at Iosan commentedI met similar issue from #49 with existing D7 site (7.82) and using entitycache module.
Updating core thanks to drush without making updatedb will revert because of this error :
In this case, do not use
drush upc
butdrush pm:update
to update code and database in the same time.Comment #64
davidhk CreditAttribution: davidhk commentedI ran into this problem, and our site is one that started on an old version of Drupal. Fix below.
After upgrading, when I ran update.php it failed with the error:
Using phpmyadmin to look at my users table, it doesn't have a 'changed' field, but I do see a 'changed' index:
Keyname: Changed
Type: BTREE
Unique: No
Packed: No
Column: access
Cardinality: 5659
Collation: A
Null: No
I dropped that index, then ran the update.php again. This time it completed without any errors.
Checking the structure in phpmyadmin shows the users table now has a 'changed' field, and a 'changed' index, and that the new 'changed' index is on the 'changed' column, as expected.
Comment #65
mfbPatch to tweak the update function, given that it seems correct for very old MySQL databases to have a "changed" index on the "access" column. Presumably this means they are also missing the "access" index on "access" column, so I add that if needed. (On Postgres, the "changed" index was dropped and a new "access" index was created, so I think this only affects MySQL.) Note, I don't have access to re-open this issue.
Comment #66
mfbp.s. Here is ye olde update function for those don't want to go poring thru tarballs: https://api.drupal.org/api/drupal/modules%21system%21system.install/func...
Comment #67
davej CreditAttribution: davej commentedWe had the same error as #49 on multiple sites when applying the 7.86 or 7.87 update to sites on the previous security update version, 7.82 . One or two were very old sites that started on Drupal <= 4.6, most were not. Applying #55 + #65 + https://www.drupal.org/project/drupal/issues/3107295#comment-13980549 (separate issue affecting multiple sites) resolved it.
Comment #68
Collins405 CreditAttribution: Collins405 commentedJust ran into the same issue upgrading from 7.82 to 7.87. WSOD
This is a Drupal 7 multisite, started on Drupal 7, no changes ever made to the users table.
PDOException: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'base.changed' in 'field list': SELECT base.uid AS uid, base.name AS name, base.pass AS pass, base.mail AS mail, base.theme AS theme, base.signature AS signature, base.signature_format AS signature_format, base.created AS created, base.changed AS changed, base.access AS access, base.login AS login, base.status AS status, base.timezone AS timezone, base.language AS language, base.picture AS picture, base.init AS init, base.data AS data FROM {users} base WHERE (base.uid IN (:db_condition_placeholder_0)) ; Array ( [:db_condition_placeholder_0] =>1 ) DrupalDefaultEntityController->load() in includes/entity.inc
Comment #69
cilefen CreditAttribution: cilefen at Institute for Advanced Study commentedComment #70
mcdruid@Collins405 I've commented in the issue you filed that @cilefen linked.
That's slightly different to the recent discussion here, which is instead about the fact that some sites may have something in their schema (e.g. an index or column) that conflicts with the schema update in
user_update_7020()
.Comment #71
andrewfn CreditAttribution: andrewfn as a volunteer commentedI am pleased to say I have got to the bottom of the problem which was preventing this update working on most of my Drupal 7 websites.
A while ago there was a patch to the user table which updated the schema_version number to 7020. I had applied this patch to most of my D7 sites. This new update in 7.83 checks the schema_version, (expecting it to be 7019) and thinks the update has already been done.
The solution is to put the schema_version back to 7019 and run the update again. This worked flawlessly on every one of my sites.
Thanks to mcdruid above for the code.
Comment #72
izmeez CreditAttribution: izmeez commentedI have added the following comment to the Issue Summary:
Comment #73
mcdruidThanks for all the comments and investigation.
It looks like the most common problem scenario is an existing index called
changed
on theaccess
field, and #65 looks like a good solution for that.However, it seems that some sites will have an existing
changed
field that conflicts with the update.I'm not certain we can cater for every such eventuality, but here's a patch that tries to alter an existing field to match the new schema.
We'd hope that in most situations this will preserve any data that's already in that column. However, I suppose it's possible there'd be a problem if the existing schema is significantly different.
I'll do some manual testing.
It may be a more robust option to drop the
changed
field if it's already there and create it again, discarding any existing data in the process (and replacing it with the default value that matches theaccess
field).Anyone have a strong preference for either option?
Comment #74
mcdruidI've done some basic manual testing with MySQL and SQLite, putting an index and / or field "in the way" of this update and running it.
So far it's worked okay in every scenario I've tried.
I am considering changing the logic to drop and recreate instead of using
db_change_field()
when there's already achanged
field though, as I suspect that's less likely to cause a problem, and the data in that column should not be precious.Comment #75
izmeez CreditAttribution: izmeez commented@mcdruid While I appreciate the fix for this issue has caused more grief than expected I would take issue with the assertion that
This issue is in it's 10th year and the opening issue summary and other comments have explained the rationale and usefulness of the change to some platforms. It may be presumptuous to assume the existing data is not important, at least to some sites. An approach that preserves existing data would be preferable and if needed possibly an alert on update where a conflict cannot be resolved directing people to this issue and the various solution contained might be better.
I would urge for more input to this question by those who this might directly impact.
Thank you.
Comment #76
hargobindThe patch in #73 appears to work great in my quick testing, and the code looks like it addresses the issues mentioned so far. I don't personally feel comfortable marking RTBC because I haven't done the rigorous testing that a core commit deserves.
I agree with @izmeez that it's better to make the change without destroying existing data because it's highly likely that anyone who has already applied this patch in the past would like to keep the data that's already there. Plus, imagine a website that is user-centric where the changed date is shown on a user's profile. If we were to delete the data in that column, the date would change, and that might be confusing/concerning to users.
Comment #77
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedTwo questions, besides that RTBC.
Question:
Why is the inner if() dependent on the outer if.
Don't we always want to add the index on 'access' when it does not exist?
Will db_change_field() also add the index?
Comment #78
mcdruidGood questions!
1) Yes I suppose we would want to create the index on access if it didn't exist. The nested if is based on the assumption that it only won't exist if it's there but called something else.
2) IIUC
\DatabaseSchema::addField()
will create the index e.g. by calling\DatabaseSchema_mysql::createKeysSql
https://git.drupalcode.org/project/drupal/-/blob/7.87/includes/database/...
I had to check, but yes
db_change_field()
will also do the same if there are keys in the schema:https://git.drupalcode.org/project/drupal/-/blob/7.87/includes/database/...
Do you want a change based on 1 or shall we go ahead with #73? I think I'm happy as it is.
Comment #79
Fabianx CreditAttribution: Fabianx as a volunteer and at Tag1 Consulting commentedRTBC for #73 - in practice probably no one has the index on access missing that does not also have an index on changed ...
Comment #81
mcdruidThank you everyone that helped out with this follow up.
Comment #82
eelkeblokFWIW, we're running into the missing column (much like as reported in #62 and #68) because we are doing a drush vset maintenance_mode 1 at the start of our deployment process, which seems to be loading a user object somewhere along the bootstrap process. Not sure yet if this is because our particular setup or a more generic problem. One would think that should be a pretty common setup.
Comment #84
millisaeubanks CreditAttribution: millisaeubanks commentedI am still having this issue on a Drupal 7 multisite.
My default_users table was updated and the default_system table had the updated module number. But the _users & _system tables for my two other sites were not updated.
I tried running the update statement above and reinstalling the 7020 update and still no luck.
Comment #85
manuelangelrp CreditAttribution: manuelangelrp commentedI have some problems updating from 7.56 to 7.90 in a multisite instance. I resolved with this sequence:
Comment #86
hargobind@millisaeubanks Updates on a multi-site need to be run on each separate site, e.g. you'll need to run the update at example1.com/update.php as well as example2.com/update.php, etc.
Comment #87
tondeuse CreditAttribution: tondeuse as a volunteer commentedHere is the commented scripted solution I have introduced inside my deployment process inside a small shell script. It will need to run once in every environment in order to be able to upgrade all my Drupal sites from 7.73 to 7.92. I will remove it once 7.92 is in production. Thanks to all for the input and inspiration.