1

I need to make a correction to a hook_update_N() function in the .install file which is causing SQL constraint errors when some users upgrade to the new release version. The original worked fine providing they ran update.php manually right after upgrading. But some users started using the site before running update.php and then when the did run it they get SQL errors. Also some automated upgrade scripts get the error. In both cases the required update is not performed.

Backgorund details are in issue https://www.drupal.org/node/2706119

The correction is done and ready, but I do not necessarily want to make another release, as it was only three months ago for the last release. 18k users have upgraded but 34k have not yet, so it would be good if the fixed update_n() function could somehow be added into the current release. Is that possible? Can git tag the new commit into current version and then I re-release it again?

  • 2
    As far as I recall, you cannot create the same release twice; you need to create another release. You could delete the last release and recreate it, but I am not sure the Update manager module would notify users of a new release; if it did, I guess users would be confused about being notified of a new version that is the same they have. – kiamlaluno Jul 11 '16 at 9:26
  • Thanks kiamlaluno, yes I agree even if I could delete and re-create the release I think the confusion for all users would be a worse outcome than simply inconveniencing the 18k users who have already upgraded to 1.4 to have to upgrade again to 1.5. There are eight other issues fixed so a new release does give them something. And for the 34k users who have not upgraded they can simply go straight from 1.3 to 1.5 and avoid the sql error. I am new here - how do I give you credit for the response? – Jonathan1055 Jul 12 '16 at 7:36
0

Talking as project administrator on drupal.org, as far as I recall, you cannot create the same release twice; you need to create another release. You could delete the last release and recreate it, but I am not sure the Update manager module would notify users of a new release; if it did, I guess users would be confused about being notified of a new version that is the same they have.

If I understand correctly, the issue is that your update hook contained the following code.

   $rows_updated = db_update('role_permission')
     ->fields(array('permission' => 'schedule publishing of nodes'))
     ->condition('permission', 'schedule (un)publishing of nodes', '=') ->execute();

  return format_plural($rows_updated, '1 row updated in role_permission table.', '@count rows updated in role_permission table.');

Then, you changed it to the following one.

 // Updates done in two stages to avoid integrity constraint violation.
 // @see http://www.drupal.org/node/2706119

 // Select all role ids which already have the new permission value.
 $query = db_select('role_permission', 'rp')
   ->fields('rp', array('rid', 'permission'))
   ->condition('permission', 'schedule publishing of nodes');

 // Delete the rows for these roles which also have the old permission value,
 // as these are no longer needed and should not be updated to the new value.
 $rows_deleted = 0;
 if ($rows_to_delete = $query->execute()->fetchCol()) {
   $rows_deleted = db_delete('role_permission')
     ->condition('rid', $rows_to_delete, 'IN')
     ->condition('permission', 'schedule (un)publishing of nodes', '=')
     ->execute();
 }

 // Now update any other rows which still have the old permission value.
 $rows_updated = db_update('role_permission')
   ->fields(array('permission' => 'schedule publishing of nodes'))
   ->condition('permission', 'schedule (un)publishing of nodes', '=')
   ->execute();

 return format_plural($rows_deleted, '1 row deleted', '@count rows deleted')
   . ', ' . format_plural($rows_updated, '1 row updated', '@count rows updated')
   . ' ' . t('in role_permission table');

As I understand it, the new code is supposed to replace the old code, and your problem is that there are users who already run the update the update #7102. If that is the case, then I would rename scheduler_update_7102() (with the new code) scheduler_update_7103(). In this way:

  • The users who didn't do the update will not run the old scheduler_update_7102() and they will not get the error
  • The users who already ran scheduler_update_7102() will find scheduler_update_7103() which completes the update for them.
  • Thanks @kiamlaluno, that is exactly what I am going to do. I had just tested this myself, before I saw your answer and was about to post it here. I realised that it does not matter if the users who have run the old 7102 without any problems also run the new version 7103. Also it is OK for the .install file to miss out 7102 - users who have yet to upgrade to 1.4 will just go straight to 1.5 and run 7103. – Jonathan1055 Jul 12 '16 at 10:50
  • 1
    For the record I found drupal.org/node/128614 which states that you cannot alter a release. – Jonathan1055 Jul 27 '16 at 8:38
2

You can reset the status of the hook_update_n from below query update system set schema_version=0 where name='modulename(hook)';

Then you can run update.php so this hook_update_n() will work again with your latest changes.

Also you can see this link for schema_version values system_schema() why we have to set schema_version '0' instead of '-1'.

you can use following drush module for roll back the update version in the system table. Called "uroll" for update rollback.

https://github.com/danshumaker/drush-uroll

Usage: drush uroll --module=mycustommodule --version=5

This combined with a database backup reload script allows you to rinse and repeat when writing update functions

  • Err, is that really a good idea? There's no mention of this being the only hook_update_n() function, so all of the previous ones will also be run. That might not be desirable... – Clive Jul 11 '16 at 10:09
  • no all previous updates would not run because we are passing only that module name in where clause. so only that module's hook_update_n() will run – Yogesh Pawar Jul 11 '16 at 10:14
  • 1
    Exactly my point. So an install file has: MYMODULE_update_7100() { delete_everything(); } followed by MYMODULE_update_7101() { do_something_minor(); }. OP is trying to "fix" 7101. Why would they want 7100 to run as well? – Clive Jul 11 '16 at 10:26
  • we don't want to run 7101, using that update in system table we can reuse the 7100 once again. no need to write 7101. – Yogesh Pawar Jul 11 '16 at 11:14
  • I don't think you're following what I mean. If you set the current schema to 0, then 7100 and 7101 will both run. If you're suggesting that the entire install file be rewritten and all, potentially dozens, of update functions should be merged into a single, new, update function (7100), then that's a bad idea for all sorts of other reasons. And it still doesn't solve the major problem - the updates from the previous hooks have already been run. They should not be run again. – Clive Jul 11 '16 at 11:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.