The Problem
When building an installation script for your software you usually have to create the required database tables. This is easy to do with running simple DB queries. Works great when installing first version. But once you have to start upgrades it can quickly become a nightmare.
Of course you can't always create the tables from scratch because the user might already have some data in them! So you have to update them by adding the new fields only.
The Typical Solution
The usual way of handling this is storing the current version in the database, then running ALTER TABLE queries only if the version installed is older than the version when the new fields are added. This is a decent approach but rather error-prone because you have to be very careful of updating version numbers and assigning new fields to them.
The Better Approach
Instead of this, I am suggesting you the simpler approach we follow with our Wordpress plugins - for example
BroadFast for Wordpress. We do frequent upgrades there and instead of trying to match ALTER TABLE statements to version numbers, we choose a
conditional approach to adding fields in the tables. Conditional simply means that we'll check if a field is already in the table, and if not, we'll add it only then. Let's see the function:
-
-
-
- function add_db_fields($fields, $table) {
- global $wpdb;
-
-
- $table_fields = $wpdb->get_results("SHOW COLUMNS FROM `$table`");
-
- $table_field_names = array();
- foreach($table_fields as $f) $table_field_names[] = $f->Field;
-
-
- $fields_to_add=array();
-
-
- foreach($fields as $field) {
- if(!in_array($field['name'], $table_field_names)) {
- $fields_to_add[] = $field;
- }
- }
-
-
- if(!empty($fields_to_add)) {
- $sql = "ALTER TABLE `$table` ";
-
- foreach($fields_to_add as $cnt => $field) {
- if($cnt > 0) $sql .= ", ";
- $sql .= "ADD $field[name] $field[type]";
- }
-
- $wpdb->query($sql);
- }
- }
This is the whole function you need. It gets your array with fields, for each field check if it exists, and if not, adds it. The function can be called with multiple fields, but should be called once for each table where you are adding fields. Here is how to call the function:
- $fields = array(
- array("name"=>"sender", "type"=>"VARCHAR(255) NOT NULL DEFAULT ''"),
- array("name"=>"require_name", "type"=>"TINYINT UNSIGNED NOT NULL DEFAULT 0"),
- array("name"=>"auto_subscribe", "type"=>"VARCHAR(255) NOT NULL DEFAULT ''")
- );
- add_db_fields($fields, "mailing_lists");
There isn't much to comment here. The table is called "mailing_lists" and we are conditionally adding three fields to it. Note that $fields is array of associative arrays, and each of them has name and type. The field "type" contains the full list of SQL arguments for the fields, not only the type. Obviously this function works only for adding new fields. This is the most common operation when releasing upgrades. Of course, you can expand it further to support CHANGE queries (but it won't change field names).
No comments:
Post a Comment