The fastest easiest way to get it right.

Upgrade Scripts

Upgrade Scripts perform actions on the database after a build. Upgrade scripts are PHP programs that execute at superuser privelege and are especially useful for populating new columns with default values or populating a new table from data in old tables.

Naming and Placement

The recommended method for naming scripts is to use the date the script was finished plus a very short description of the feature, as in 2008-02-06-yamlspec.php or 2008-02-06-svnurl.php. Scripts are executed in the order returned by PHP's asort(), so a date-based naming system will cause them to run in the order they were written.

Scripts are PHP programs, so they should have a PHP extension. A script might be named 2008-02-06-fillempcode.php.

Scripts should be placed into the directory application/scripts, as in application/scripts/2008-02-6-fillempcode.php.

When and How They Run

Scripts run as the very last step in a build, after all other steps are complete. The builder scans the scripts directory and makes a list of all available scripts. Then it looks in the application's "scripts" table to see which have been marked as successfully completed. Any script not marked as completed will be executed.

The builder makes no attempt to determine if the script has run successfully. The script must notify the builder that it has run ok with this command:

$this->scriptSuccess();

If the script does not issue that command, it will be run every time an upgrade is performed.

Coding The Script

Scripts actually execute within a builder method. This means a script can refer directly to the builder as "$this". The basic picture of how this works is here:

class x_builder {
    //
    // code, code, code, code....
    //
    function runScripts() {
        // 
        // code, code, code, code....
        // 
        include($script_name);
    }    
}

Useful Builder Functions

There are a handful of useful builder methods available for a script to use.

$this->SQL("UPDATE ...."). Directly issues a SQL command and does not return results.

$result = $this->SQLRead("SELECT ..."). Directly issues a SQL Select and returns a result resource.

$row = $this->SQLReadRow($result). Returns one row from a previous query.

$rows = $this->SQLReadRows($query). Accepts a SQL SELECT statement and returns the complete results.

$this->logEntry("I am going to update the table now, please wait..") . Use this command to issue log entries.

$this->scriptSuccess(). Invoke this command only when you are certain everything has run OK. This command records that the script has run ok, once this command is issued the script will never be run again. If this command is not run by the script then the script will be run on the next upgrade and so on for the next upgrade until the script executes this command.

$this->checkSuccess($scriptName). Tells you if a previous script has been marked as running ok. Use this to prevent having a script run if some pre-requisite has not run.

Design Ideas

Make it Rerunnable or Indempotent

The fancy word for re-runnable is "indempotent". In plain terms this means that if every command in the script runs twice (or 8 times or 100 times) there will be no corruption, and if the script is stopped halfway through there will be no corruption.

Transactions are a very important aid here. If three commands must execute together, wrap them in a transaction.

If you are populating a new table with values from an existing table, check first to see if the table is populated and do nothing if the table has rows already.

Scripts Are Very Dangerous

The key ideas for Andromeda were born in an environment where upgrade scripts were a central feature of the development environment. Ken Downs observed that upgrade scripts were the weakest link in the entire process, for reasons too numerous to mention here. Many of Andromeda's design ideas were motivated by Ken's desire to shrink down or eliminate the role of upgrade scripts.

With that being said, every framework, no matter how strong it is, will need some way to 'escape the box' and perform actions that were not anticipated by the framework designers. While we believe that Andromeda's database build functions implement a radically powerful new way to do things, we have no illusions that the builder can do everything any programmer might ever need done on an upgrade. Upgrade scripts let the programmer fill the gaps. Nevertheless, carelessly written upgrade scripts can ruin an otherwise beautiful day!

Broken Upgrades. Because a script is code, it can have bugs. Upgrade scripts are notoriously difficult to debug because the programmer never runs the script more than a few times, and is not likely to witness any edge cases on his well cared-for dev station. This means that errors occur during an upgrade, when the person witnessing the error may have no knowledge of how to fix it. This is very much counter to the Andromeda ideal of having upgrades that are guaranteed to execute and complete. Corrupted Customer Data. Scripts run at superuser level, so a command such as "truncate table customers" will run without complaint! No Validation. One of the basic ideas behind Andromeda is that all of the business rules are expressed in a data file, which makes them far more transparent than rules that are "trapped" in code. This is not true for actions that occur inside of scripts. An upgrade script should never make table structure changes or other alterations that would invalidate the YAML specification.
comments powered by Disqus
Home |  Documentation |  Download |  Credits |  Contact |  Login
Andromeda © Copyright 2004-2013, Licensed under the GPL Version 2