[wp-trac] [WordPress Trac] #18609: term_id collisions possible with InnoDB tables and global_terms_enabled

WordPress Trac wp-trac at lists.automattic.com
Wed Sep 7 02:41:42 UTC 2011


#18609: term_id collisions possible with InnoDB tables and global_terms_enabled
--------------------------+-----------------------------
 Reporter:  andrew_l      |      Owner:
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  Taxonomy      |    Version:  3.2.1
 Severity:  major         |   Keywords:
--------------------------+-----------------------------
 This bug relates to the "global terms" feature that uses the
 wp_sitecategories table to store all terms used across the multi-site
 install. This feature is enabled by setting global_terms_enabled to "1" in
 the wp_sitemeta table.

 I have found that when global_terms_enabled is on, and you are using
 InnoDB tables, it is possible for a new term insertion in the local terms
 table (wp_x_terms) to fail due to an ID collision. This happens because
 InnoDB does not handle auto_increment in the same way as MyISAM, and the
 code for the global terms feature does not account for this difference.

 In MyISAM, any change to a value in an auto-incremented column causes the
 table's AUTO_INCREMENT value (next value to be used, as seen via "show
 table status") to change. For example, if I have a MyISAM table, and I use
 an update statement to change the value of an auto incremented column to a
 value larger than the current AUTO_INCREMENT, the AUTO_INCREMENT is
 automatically increased as needed, so the next insertion cannot collide.

 However, InnoDB does not do this. It only changes AUTO_INCREMENT on an
 insert. It does not change it when a column value is increased via an
 update statement. You can see this in the MySQL docs, or you can see it by
 creating a test case, like this:

 - Create an InnoDB table with 2 columns: ID (auto_increment, primary key)
 and data.
 - Insert a row using an insert statement, without specifying an ID.
 - Observe that ID = 1 for that row, as expected.
 - Use an update statement to set ID = 2 on that row.
 - Insert another row without specifying an ID.
 - Observe that the insertion fails. MySQL has attempted to insert a row
 with ID = 2, but there is already such a row.

 If you do the same steps with a MyISAM table, the insertion does not fail,
 because AUTO_INCREMENT was automatically changed from 2 to 3 when your
 update statement was executed.

 Going back into the context of the global terms feature: This problem
 happens when a new term is created in a site. The new term is initially
 inserted into the local terms table for the current site (wp_x_terms).
 After this, the function global_terms (in ms-functions.php) is called.
 This function finds or creates a matching entry in the wp_sitecategories
 global terms table, and uses an update statement to change the term_id of
 the row we just inserted in wp_x_terms. When wp_x_terms is an InnoDB
 table, the AUTO_INCREMENT value for the table does not change.

 Suppose the AUTO_INCREMENT value was 58 after the original insertion, and
 further suppose that 58 was (coincidentally) the ID found in
 wp_sitecategories and written into our new row by the update statement
 described above. Now suppose we are ready to insert another new term into
 wp_x_terms. AUTO_INCREMENT is still 58, so we attempt to insert a term
 with term_id = 58, but it fails because there is already a row in the
 table with that ID.

 Fix for this would be to reorder the operations so that no row is inserted
 into wp_x_terms until after wp_sitecategories has been queried and
 updated. That way, we know the ID we need to use when inserting into
 wp_x_terms before that insertion takes place, so we can specify it in the
 insert statement rather than depending on AUTO_INCREMENT.

 I have marked this as severity major, because these unpredictable term_id
 collisions can cause weird errors, and the only workaround I have at this
 time is to disable global terms and restart MySQL (to regenerate
 AUTO_INCREMENT values on all tables).

-- 
Ticket URL: <http://core.trac.wordpress.org/ticket/18609>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software


More information about the wp-trac mailing list