Assuming the foreign keys patch to the schema API makes it in, there are four ways we can approach foreign keys in Drupal 6. 1. Don't use them at all. Just provide the schema API for contrib modules with higher database requirements than core. 2. Configure foreign keys as RESTRICT on delete. This will have no effect on MyISAM, but it will improve code quality because operations creating inconsistency would fail. Such operations would then be rewritten to manipulate the database in a consistent way. 3. Configure foreign keys as CASCADE on delete and have extra PHP run whenever a query manipulates a database using MyISAM. Basically, whenever a DELETE query gets sent to a MyISAM system, we would convert it to a SELECT query to identify the rows that would be deleted. Then, we would delete the records attached with foreign keys. Finally, we would run the original DELETE query. This would have to be recursive. 4. Configure foreign keys as CASCADE on delete and have modules conditionally run queries in their deletion hooks depending on the storage engine. If a module doesn't check the storage engine type, the DELETE it runs would simply be redundant. Personally, I think #2 would be a nice first step in Drupal 6. It would at least force us to clean up the database interaction so #3 or #4 could be seamlessly added later.
On 6/3/07, David Strauss <david@fourkitchens.com> wrote:
Assuming the foreign keys patch to the schema API makes it in, there are four ways we can approach foreign keys in Drupal 6.
1. Don't use them at all. Just provide the schema API for contrib modules with higher database requirements than core.
This is the path of least resistance, but Dries said that he would consider referential integrity stuff, so we should try. 2. Configure foreign keys as RESTRICT on delete. This will have no
effect on MyISAM, but it will improve code quality because operations creating inconsistency would fail. Such operations would then be rewritten to manipulate the database in a consistent way.
This seems the most sensible given the state of affairs (MyISAM, ...etc.). 3. Configure foreign keys as CASCADE on delete and have extra PHP run
whenever a query manipulates a database using MyISAM. Basically, whenever a DELETE query gets sent to a MyISAM system, we would convert it to a SELECT query to identify the rows that would be deleted. Then, we would delete the records attached with foreign keys. Finally, we would run the original DELETE query. This would have to be recursive.
This is moving the database layer work into application code, which is not a good thing. 4. Configure foreign keys as CASCADE on delete and have modules
conditionally run queries in their deletion hooks depending on the storage engine. If a module doesn't check the storage engine type, the DELETE it runs would simply be redundant.
Same as my comment on #3. Personally, I think #2 would be a nice first step in Drupal 6. It would
at least force us to clean up the database interaction so #3 or #4 could be seamlessly added later.
Agreed. -- 2bits.com http://2bits.com Drupal development, customization and consulting.
On 3-Jun-07, at 11:14 PM, David Strauss wrote:
3. Configure foreign keys as CASCADE on delete and have extra PHP run whenever a query manipulates a database using MyISAM. Basically, whenever a DELETE query gets sent to a MyISAM system, we would convert it to a SELECT query to identify the rows that would be deleted. Then, we would delete the records attached with foreign keys. Finally, we would run the original DELETE query. This would have to be recursive.
Is MySQL's MyISAM the only database type is brain-dead when it comes to foreign key constraints? Or do some of the other light-weight dbs (firebird, sqlite) suffer this same problem? If so, we might need a way to handle this at the database abstraction layer. (Which might not be a bad idea either way.) -Angie
----- Start Original Message ----- Sent: Sun, 03 Jun 2007 22:14:53 -0500 From: David Strauss <david@fourkitchens.com> To: development@drupal.org Subject: [development] Foreign keys in Drupal 6
Assuming the foreign keys patch to the schema API makes it in, there are four ways we can approach foreign keys in Drupal 6.
1. Don't use them at all. Just provide the schema API for contrib modules with higher database requirements than core.
I do not even consider this an option.
2. Configure foreign keys as RESTRICT on delete. This will have no 3. Configure foreign keys as CASCADE on delete and have extra PHP run
OK, someone else will probably need to translate this to layman terms. But here is the thing: if we add PK support then we have a graph (DAG, actually) where the vertices are the tables and the edges are the PK relationships. In order to properly simulate RESTRICT you need to topologically sort this DAG so at any time you only delete tables that have no outgoing edges. At this point you have simulated CASCADE as well... I have the supporting code (top.sort) for this in my sandbox, originally written to replace module.weight hence the name weights.php . So, CASCADE.
Assuming the foreign keys patch to the schema API makes it in, there are four ways we can approach foreign keys in Drupal 6.
It might be worth asking Chad (hunmonk) for an opinion, since there's probably no one who has spent more time thinking about deleting Drupal "objects" from the database in a coherent manner.
On 04 Jun 2007, at 05:14, David Strauss wrote:
Assuming the foreign keys patch to the schema API makes it in, there are four ways we can approach foreign keys in Drupal 6.
1. Don't use them at all. Just provide the schema API for contrib modules with higher database requirements than core.
2. Configure foreign keys as RESTRICT on delete. This will have no effect on MyISAM, but it will improve code quality because operations creating inconsistency would fail. Such operations would then be rewritten to manipulate the database in a consistent way.
3. Configure foreign keys as CASCADE on delete and have extra PHP run whenever a query manipulates a database using MyISAM. Basically, whenever a DELETE query gets sent to a MyISAM system, we would convert it to a SELECT query to identify the rows that would be deleted. Then, we would delete the records attached with foreign keys. Finally, we would run the original DELETE query. This would have to be recursive.
4. Configure foreign keys as CASCADE on delete and have modules conditionally run queries in their deletion hooks depending on the storage engine. If a module doesn't check the storage engine type, the DELETE it runs would simply be redundant.
Personally, I think #2 would be a great first step. We could then consider #3 or #4 for Drupal 7. -- Dries Buytaert :: http://www.buytaert.net/
David Strauss <david@fourkitchens.com> writes:
Assuming the foreign keys patch to the schema API makes it in
I created http://groups.drupal.org/node/4328 to discuss this exact topic. There is no patch yet.
there are four ways we can approach foreign keys in Drupal 6.
+1 for RESTRICT. In theory, the code is already behaving this way. In practice, I'm sure we'll find lots of ways it is not. We'll have our hands full just fixing those bugs (once we also fix all the INSERT/UPDATE bugs preventing ref integrity in the first place). I don't think we can or should ever support CASCADE until we require databases that support it, but that is a topic for a different day. Barry
David previously listed four options for using foreign keys in Drupal on this mailing list. I previously voted in favor of making foreign keys RESTRICT on delete so the database simply refuses to delete a row that is a foreign key of another table row. I now realize that isn't possible. When we disable a module, we do not delete its tables, but we stop calling its hooks. e.g. In RESTRICT mode, if we disable the book module, it becomes impossible to delete any node previously in a book because the book table will have a row with a foreign key into the node table for that node. Not good. (Incidentally, this also reveals that node_delete() will need to call nodeapi('delete') before deleting the row from the node table.) This leaves us to choose between not using foreign keys at all or using CASCADE on delete. If we use CASCADE and rely on it to delete rows, we will have to implement the cascading-delete logic within Drupal itself for engines that do not support it. I don't think we want to deal with this. Also, it will require using an abstract API for all DELETE SQL queries which many here have opposed for anything but DDL statements. Frankly, the more I think about it, the more I realize referential integrity is just not doable for Drupal 6. However, if we still want to try, my suggestion is: 1. We set foreign keys as CASCADE on delete. 2. We specify that modules MAY NOT depend on the CASCADE deletion; they must continue to execute their own DELETE queries, because the db engine may not support CASCADE deletion. The DELETE queries will be redundant but harmless (deletion is infrequent enough not to be a performance issue, right?). 3. On engines that do support CASCADE deletion, the fact that we are using CASCADE means that deleting nodes or other objects referenced by disabled modules will continue to work; the dependent rows will be deleted. On non-supporting engines, the rows created by disabled modules will continue to exist, but that is just status quo. Comments? Barry
Quoting Barry Jaspan <barry@jaspan.org>:
Comments?
+1 Cascade. Better use by all modules for the uninstall API is needed. I can see the points for not uninstalling when disabled but I am upset that no Uninstall is available for any module enabled that adds tables or columns to existing tables. Earnie
Options for disabling: * "do you wish to clear all inserted data?" * system should always run "delete" even if it is disabled Options for uninstall: * if it detects that the DB has data for this module, the system will warn the user and the best thing he can do is "allow the uninstall to clear all data" or "just leave the module disabled" Fernando On 6/13/07, Earnie Boyd <earnie@users.sourceforge.net> wrote:
Quoting Barry Jaspan <barry@jaspan.org>:
Comments?
+1 Cascade.
Better use by all modules for the uninstall API is needed. I can see the points for not uninstalling when disabled but I am upset that no Uninstall is available for any module enabled that adds tables or columns to existing tables.
Earnie
"Fernando Silva" <fsilva.pt@gmail.com> writes:
Options for disabling: * "do you wish to clear all inserted data?"
If we use RESTRICT on delete, the only possible answer to that question is "yes", so this would just be a standard confirmation screen. Also, since we will have to clear all a module's data when it is disabled, we'd be making "disable" the same as "uninstall." Do people think eliminating the "disabled" state so only installed/uninstalled states exist is a good idea?
* system should always run "delete" even if it is disabled
This would mean that even disabled modules get parsed and executed; that violates my sense of what "disabled" means (and re-introduces performance penalties eliminating by .info files). Thanks, Barry
Quoting Barry Jaspan <barry@jaspan.org>:
"Fernando Silva" <fsilva.pt@gmail.com> writes:
Options for disabling: * "do you wish to clear all inserted data?"
If we use RESTRICT on delete, the only possible answer to that question is "yes", so this would just be a standard confirmation screen. Also, since we will have to clear all a module's data when it is disabled, we'd be making "disable" the same as "uninstall."
-1 for uninstall on disable.
Do people think eliminating the "disabled" state so only installed/uninstalled states exist is a good idea?
No. I may want to disable a module for a moment then continue using it after some modification or time period.
* system should always run "delete" even if it is disabled
This would mean that even disabled modules get parsed and executed; that violates my sense of what "disabled" means (and re-introduces performance penalties eliminating by .info files).
I haven't looked to see the changes yet for D6 but for D5 the module is included even if it is disabled. This also violates my sense of what "disabled" means. I've been bitten by this before. Back to the delete hook. If I have the module installed but disabled and I have node dependencies in my module table then I would want my module table data delete with the node. What if we consider, [Deactivate] and [Disable] where [Deactivate] causes your idea of all data being removed and [Disable] leaves the data in place? If disabled the delete hook is still called while a deactivated module has no affect since it no longer has data. Earnie
Earnie, I don't think you are correct on this point. In Drupal 4.7.x, a module was included even when disabled only on the /admin/modules page. In 5.x, it should never be included. http://api.drupal.org/api/5/function/module_load_all http://api.drupal.org/api/5/function/module_list -Peter On 6/13/07, Earnie Boyd <earnie@users.sourceforge.net> wrote:
I haven't looked to see the changes yet for D6 but for D5 the module is included even if it is disabled. This also violates my sense of what "disabled" means. I've been bitten by this before.
Earnie
Quoting Peter Wolanin <pwolanin@gmail.com>:
Earnie, I don't think you are correct on this point. In Drupal 4.7.x, a module was included even when disabled only on the /admin/modules page. In 5.x, it should never be included.
http://api.drupal.org/api/5/function/module_load_all http://api.drupal.org/api/5/function/module_list
-Peter
On 6/13/07, Earnie Boyd <earnie@users.sourceforge.net> wrote:
I haven't looked to see the changes yet for D6 but for D5 the module is included even if it is disabled. This also violates my sense of what "disabled" means. I've been bitten by this before.
I stand corrected. Maybe it was prior release versions where I experienced this issue. I have a patch in the issue queue for breaking out module_list to module_list_all and module_list_bootstrap because bootstrap calls module_list twice and pulls from the DB twice with $refresh set to TRUE. Reference http://drupal.org/node/116820 for more information on that. Earnie
Earnie Boyd <earnie@users.sourceforge.net> writes:
+1 Cascade.
Better use by all modules for the uninstall API is needed.
I cannot parse this sentence.
I can see the points for not uninstalling when disabled but I am upset that no Uninstall is available for any module enabled that adds tables or columns to existing tables.
We could certainly declare hook_uninstall() to be mandatory for any module that declares hook_install(); now that we have drupal_uninstall_schema(), hook_uninstall() is usually trivial (actually, it always was trivial). For that matter, we could provide a default hook_uninstall() that drops all the module's tables. I think the new variable patch also identifies variables by module so we could uninstall them automatically as well. This has nothing really do to with foreign keys, though. Thanks, Barry
Quoting Barry Jaspan <barry@jaspan.org>:
Earnie Boyd <earnie@users.sourceforge.net> writes:
+1 Cascade.
Better use by all modules for the uninstall API is needed.
I cannot parse this sentence.
I'm just saying that the admin/build/modules/uninstall view hasn't had anything on it for any of the modules I've used. If modules used the appropriate hook to uninstall its data the user could remove the tables at will.
I can see the points for not uninstalling when disabled but I am upset that no Uninstall is available for any module enabled that adds tables or columns to existing tables.
We could certainly declare hook_uninstall() to be mandatory for any module that declares hook_install(); now that we have drupal_uninstall_schema(), hook_uninstall() is usually trivial (actually, it always was trivial).
This sounds good.
For that matter, we could provide a default hook_uninstall() that drops all the module's tables. I think the new variable patch also identifies variables by module so we could uninstall them automatically as well.
This sounds better.
This has nothing really do to with foreign keys, though.
No but you had made statements about uninstalling tables. The API exists, it currently isn't used by many. I was just trying to point out what I've observed in regard to the statements you were making. Earnie
participants (10)
-
Angela Byron -
Barry Jaspan -
Chris Johnson -
David Strauss -
Dries Buytaert -
Earnie Boyd -
Fernando Silva -
Karoly Negyesi -
Khalid Baheyeldin -
Peter Wolanin