I'm writing my first Drupal module, and I have a question about uninstallation.

I read that the correct way to uninstall the custom schema is by calling drupal_uninstall_schema(). However, it appears from the documentation (which is cut-and-pasted from the install documentation) that this function does not call hook_schema_alter().

Does this mean that any tables altered by hook_schema_alter() will still be altered after the module is uninstalled? If so, how would one fix this? The $schema array doesn't appear to be available to the uninstall function, so unsetting the array member that you altered wouldn't work.

My module would add a field to the {users} table, so this would be an issue for me.

Comments

Mav-im’s picture

hook_schema_alter() only provides information about table changes made in your module. It doesn't alter the table in DB by itself, to make real table altering you'll need to use db_add_field() function on hook_install() and db_drop_field() on hook_uninstall() on your custom module.
Don't confuse the concept of module install/uninstall and enable/disable. First time you enable your module on admin/build/modules it will be installed (hook_install will be called). After that you can disable it, but it's still installed (tables are still altered/created). If you want to uninstall the module then go to Uninstall page on admin/build/modules and uninstall the module (on uninstall submition hook_uninstall will be used).

So if you just altering some table in your module you don't need to use drupal_uninstall_schema() function, take a look on the code:

function {your_module}_schema_alter(&$schema) {
  $schema['users']['fields']['my_field'] = array(
    'type'      => 'int',
    'size'      => 'tiny',
    'not null'  => TRUE,
    'default'   => 0,
  );
}

/**
 * Implementation of hook_install().
 */
function {your_module}_install() {
  $ret = array();
  $new_schema = array();
  // Get {users} table altering provided by your module
  {your_module}_schema_alter($new_schema);
  foreach ($new_schema['users']['fields'] as $name => $spec) {
    db_add_field($ret, 'users', $name, $spec);
  }
}

/**
 * Implementation of hook_uninstall().
 */
function {your_module}_uninstall() {
  $ret = array();
  $new_schema = array();
  {your_module}_schema_alter($new_schema);
  foreach ($new_schema['users']['fields'] as $name => $spec) {
    db_drop_field($ret, 'users', $name);
  }
}

That is the common way to alter a table provided by another module.

Jaypan’s picture

hook_schema_alter() only provides information about table changes made in your module. It doesn't alter the table in DB by itself

Are you sure about that? The documentation for hook_schema_alter() says:

Perform alterations to existing database schemas.

When a module modifies the database structure of another module (by changing, adding or removing fields, keys or indexes), it should implement hook_schema_alter() to update the default $schema

I've never used the hook myself, but I dug around through the hook_install() code and the hook_uninstall() code and couldn't find any calls to hook_schema_alter, so on one hand I could see how it could just be used for referential purposes, but on the other hand, what's the point?

I'm kind of curious about this all now.

Mav-im’s picture

I used it many times. hook_schema_alter and hook_schema provide the structure of the table. This structure information can be very helpfull if you're using drupal_write_record() function in your module to store records in table. Take a look on the drupal_write_record() realization and if you are familiar with drupal form API (especially with #tree and #parent parameters), you'll see the true power of using hook_schema and hook_schema_alter with drupal_write_record.

Karlheinz’s picture

Yes, I was going to use drupal_write_record() to do all my database calls, instead of writing the SQL myself. Seems much cleaner that way.

I had just assumed that hook_schema_alter() would change the database itself, since the examples I've seen only call it in the module's .install file. I guess not.

It turns out I might actually not alter the {users} table anyway. I was going to use it to store an API key, but I think it makes more sense to just use a site-wide API key for what I'm doing, and I'd probably store that as a variable.

EDIT: How does drupal_write_record() handle one-to-many relationships? Would I have to call it three times to update the three tables? I think that's the case, but I'm probably missing something.

-Karlheinz

Mav-im’s picture

At the end of drupal_write_record() realization you can see the db_query() call. So one call = one SQL-query.
Yes, to update 3 tables you've to call it 3 times.
This function is not a magic, it just provides some usefull functionality (if you understand, how it works).

Karlheinz’s picture

Cool beans, I think I have a handle on it now.

I wonder why the API's node_example.module doesn't use this in node_example_insert() and so forth? It would make a lot more sense.

I did find one, small, "gotcha" with using drupal_write_record(). Sometimes (though not in my case) you want to allow other modules to manipulate your SQL calls, so you wrap them in db_rewrite_sql(). You can't do that with drupal_write_record().

The only time I could see this being useful is when your module makes a node listing by querying the {node} table - if you don't wrap your SQL, the node access rules will be bypassed, because the core node module wouldn't have a chance to exclude them from the query results.

It also might mess with custom modules' abilities to add custom fields to your node (as with CCK and image_attach). Maybe. I'll have to look into that.
EDIT: Apparently not, I couldn't find any contributed modules that use hook_db_rewrite_sql().

-Karlheinz

Jaypan’s picture

I still don't get it. If hook_schema_alter doesn't actually alter the schema, what's the point of it?

Edit: Ok, I get the point of it. I did more reading to see how it works. The hook doesn't actually do anything in and of itself, but is rather just used as a point of reference to see exactly how a module is interacting with other modules. It's not meant to be called programmatically, rather just as a visual reference.

nclavaud’s picture

Just to clarify : hook_schema_alter is called actually (see drupal_get_schema() or Mav-im code above) and does alter the schema (but not the database).

Both (schema and database) shouldn't be confused. Schema is only here to provide information about the database. Altering the schema doesn't mean altering the database.