UPDATED to mark as [SOLVED]
I've just changed the Persistent Storage schema for a module, and I'm wondering the best way to handle the module upgrade function. I can see a few options:
1) Uninstall then reinstall the module. Nasty, but will work.
2) Drop then recreate the table using SQL in the Upgrade function. Don't like this because it will delete data unnecessarily, and I'd have to somehow work out how to decide which of the SQL scripts to run based on whatever storage engine was in use. Seems like I'm trying to do too much at the low level here.
3) Drop the unused columns from the database. Seems easy enough, but again I'm in a low level where I need to know what storage engine is in use.
4) Leverage some G2 functions I can't find mentioned anywhere to achieve the desired result for me...
What's the generally accepted way of modifying a schema? I've looked through a lot of modules, and I can't see one that appears to be doing this so there's nothing for me to work from.
Posts: 32509
have you looked at modules/core/classes/GalleryStorage/DatabaseStorage/schema/xml-src/A_* files.
also, you have to increment the minor version of your class.
an example:
a week ago we changed the g2_derivative table.
how? we changed the minor version in modules/core/classes/GalleryDerivative.class and we added a new class member "_isBroken" to the file.
then we generated the new interface and sql with gmake.
finally we created an alter table statement by creating the and writing the modules/core/classes/GalleryStorage/DatabaseStorage/schema/xml-src/A_GalleryDerivative_1_0.xml file. then we ran gmake in this directory and in modules/core/classes/GalleryStorage/DatabaseStorage/schema/platform/ and it created the db specific alter table statements in the mysql, oracle, ... subdirectories.
just do the same in your own module.
Posts: 431
Thanks for that - I'd got everything except the alter table statements in the A_ files. I'll give it a go and see how much damage I can do to my database!
Posts: 431
That worked great - thanks.
Just one thing, is it possible to rename a column without dropping and adding it back? Ideally I'd like to keep the data that's already there.
Posts: 32509
i'd do that in two version changes.
e.g. current version 0.9.0
in 0.9.1 add member x_new, copy data from x to x_new
in 0.9.2 remove member x
the end user sees only a version bump from 0.9.0 to 0.9.2, internally, you have two steps internally.
of course we could extend our xml transform code to allow renaming in a single upgrade, but is it really necessary?
Posts: 431
No - not necessary to extend the transform code. I'm just not sure how the two steps work with the schema. Wouldn't the user have to upgrade twice in order to run both schema updates?
Posts: 32509
see the while loop starting at line 1552 in modules/core/classes/GalleryStorage/DatabaseStorage.class
it upgrades your database table as long as there is a new A_...sql file available for it.
if your class name is GalleryPaypal and your current version of the class is 1.0, then just create a A_GalleryPaypal_1_0.xml for the 1.0 -> 1.1 upgrade and a A_GalleryPaypal_1_1.xml for the 1.1->1.2 upgrade.
hmm, ok, there's still a problem. you can't do anything in between.
you either have to tell people to reinstall your module or we have to add a rename option in the xml.
Posts: 32509
hmm, this is a hack:
have a A_GalleryPaypal_1_0.xml definition which creates the new column
in the 0.9.10 -> 0.9.11 upgrade code, you then copy the data from column a to b.
when you're done upgrading to 0.9.11, set the Schema version entry manually from 1.1 to 1.2.
also set the module _version in pluginparam map manually to 0.9.11
have another file A_GalleryPaypal_1_2.xml which removes the old column name
in module.inc, bump the version from 0.9.10 to 0.9.12
from the users perspective:
user goes to site admin -> module, sees that an upgrade is required.
user clicks upgrade, it doesn't upgrade to 0.9.12 directly, as it should, it upgrades to 0.9.11.
then he has to click upgrade again, from 0.9.11 to 0.9.12.
wow, this is a huge hack, not even sure if it works.
maybe just advice to reinstall the module and default to default values in the upgrade code and drop the old column right away.
if we decided to add rename capability, it would take a while anyway.
Posts: 431
I think I'm just going to accept the data loss and drop the column - it's not really that critical. It was just a 'nice to have'. Thanks for all the insight into how this works though!
Posts: 431
OK - another couple of questions here:
1. What happens if I have two updates to my schema over various versions (say 1.0 - 1.1 - 1.2), each of which is correctly set up with the A_ files, but a user upgrades directly from 1.0 to 1.2? Do the changes get sequentially applied (looks like the user went 1.0-1.1-1.2) or do I have to write another A_ file to handle the direct 1.0-1.2 case?
2. Do the schema updates happen before or after the upgrade function in module.inc? (I think it's before, but I just want to check).
Posts: 32509
1. as i explained in an earlier post: it's a single while loop which appliea the schema updates right one after another. after the 1_0 updates it updates the schema table entry with version entry with 1.1. then in the next loop it looks for a 1_1 update and applies it. etc.
2. see GalleryModule.class installOrUpgrade()
the db schema is updated before the update code is applied.
This whole issue here seems to indicate a problem in our upgrade code.
Perhaps we need to change how this works. E.g. don't upgrade the db schema at once.
But the issue is quite complex.