Archive for the ‘MySQL’ Category

Set MySQL connection variables with mysql-proxy

Tuesday, June 1st, 2010

We recently moved the application I work on everyday to Amazon Web Services and bravely adopted their Relational Database Service (RDS) and have had little trouble thus far, but the other day I noticed since we kicked into BST, timestamps in the database where an hour behind. Low and behold, the default time zone cannot be changed. Luckily, we’ve been using mysql-proxy since we migrated and rather than changed our application, I managed to knock up a lua script that sets the timezone variable on every query. It would be nice if it could do it when it creates a connection, but I’ve not worked out how to do that yet!

---
-- read_query() can rewrite packets
--
function read_query( packet )
        if string.byte(packet) == proxy.COM_QUERY then
                proxy.queries:append(1, string.char(proxy.COM_QUERY) .. "SET time_zone = 'Europe/London'", {resultset_is_needed = true})
                proxy.queries:append(2, packet)
                return proxy.PROXY_SEND_QUERY
        end
end

---
-- read_query_result() is called when we receive a query result
-- from the server
--
function read_query_result(inj)
        if (inj.type == 1) then
            return proxy.PROXY_IGNORE_RESULT
        end
end

If anyone could point me in the general direction for setting the variable at connection time, it’d be appreciated. I assume I can create a create_connection function, but I don’t know where to go from there.

PHP Versions in popular Linux Distributions

Thursday, May 8th, 2008

I had a problem today at work, I’ve been coding exclusively in PHP5.2 since it was available and most of the servers I’ve been working for are Debian or Ubuntu based, so I didn’t have any problems until this afternoon. We’ve recently bought a SAN solution from Dell and to gain support we bought two new servers, both with SUSE Enterprise Linux installed, which only comes with PHP 5.1.2. That particular version came out in January 2006. Since then I’ve been using the new DateTime object, the filter functions, memory_get_peak_usage() and sys_get_temp_dir(). And they’re only the problems I noticed. We could install from source, but then we lose the subtle benefits of package management.

So, this lead to me wondering what LAMP versions the popular distros are using, with the help of DistroWatch, I compiled this table. It only shows the community/open source distributions, the commercials counterparts for each are usually at least a year behind, guaranteeing support but only for out of date versions.

Distribution Version Apache MySQL PHP
Ubuntu 8.04 LTS Hardy Heron 2.2.8 5.0.51a 5.2.4
openSUSE 10.3 2.2.4 5.0.45 5.2.4
Fedora 8 Werewolf 2.2.6 5.0.45 5.2.4
Debian GNU/Linux 4.0 Etch 2.2.3 5.0.32 5.2.0
Mandriva Linux 2008.1 2.2.8 5.0.51a 5.2.5
Knoppix 5.3.1 2.2.8 5.0.51a 5.2.3
Slackware Linux 12.0 2.2.4 5.0.37 5.2.3
Gentoo Linux 2007.0 2.0.58 5.0.38 5.2.2
FreeBSD 7.0 RELEASE 2.2.6 5.0.45 5.2.5

How To: Simple database migrations with Phing and DbDeploy

Monday, April 14th, 2008

Introduction

This How To will introduce some simple database migrations to your PHP application. Ruby on Rails is a popular web application framework, that provides a method of migrating (upgrading) the applications database programatically, keeping the database schema essentially version controlled. This allows individual developers to update their working databases and the databases on testing, staging or production machines to be updated with new versions of applications. The CakePHP framework has recently developed a migrations library simliar to rails, but this article focuses on using seperate tools to run database migrations, a build tool called Phing, along with a method for creating database migrations, dbdeploy.

Install Phing

I always use the beta or release candidate of phing and for the purposes of this article I suggest you do too. The best way to download and install phing is using PEAR. This can be done on Linux or Windows assuming you have the pear script in your PATH with three shell commands.

shell> pear channel-discover pear.phing.info
shell> pear config-set preferred_state beta
shell> pear install phing/phing

Example Application structure

As an example, we’re going to develop a simple application with the following directory structure.

example/
 |-- db/
 |   `-- deltas/
 |-- deploy/
 |   `-- scripts/
 |-- library/
 `-- public/

The db directory contains sql files for using and manipulating our database and
the deploy directory contains our build scripts that set the migrations in motion. The library directory contains our application code and the public folder will contain scripts and files accessible directly from the web, but will not be the focus of this article.

Build scripts

This section shows you how to develop the build scripts that will run the database migrations. The first file we need to create is a simple configuration file and should be fairly self explanatory. The file is written as key=value, lines beginning with a # are comments. Open your editor and save the following text as deploy/build.properties.

# Property files contain key/value pairs
#key=value

# This dir must contain the local application
build.dir=../

# Credentials for the database migrations
db.host=localhost
db.user=user
db.pass=password
db.name=example

# paths to programs
progs.mysql=/usr/bin/mysql

The next file we are going to create is the deploy/build.xml file. This is the file that tells Phing what we want it to do. I’m not going to go into too much detail describing each part of the build file, there are some comments, but you should consult the Phing Documentation for further details and enhancements.

<?xml version="1.0" ?>
<project name="PurpleMonkey" basedir="." default="build">

    <!-- Sets the DSTAMP, TSTAMP and TODAY properties -->
    <tstamp/>

    <!-- Load our configuration -->
    <property file="./build.properties" />

    <!-- create our migration task -->
    <target name="migrate" description="Database Migrations">  

        <!-- load the dbdeploy task -->
        <taskdef name="dbdeploy" classname="phing.tasks.ext.dbdeploy.DbDeployTask"/>

        <!-- these two filenames will contain the generated SQL to do the deploy and roll it back-->
        <property name="build.dbdeploy.deployfile" value="deploy/scripts/deploy-${DSTAMP}${TSTAMP}.sql" />
        <property name="build.dbdeploy.undofile" value="deploy/scripts/undo-${DSTAMP}${TSTAMP}.sql" />

        <!-- generate the deployment scripts -->
        <dbdeploy
            url="mysql:host=${db.host};dbname=${db.name}"
            userid="${db.user}"
            password="${db.pass}"
            dir="${build.dir}/db/deltas"
            outputfile="${build.dir}/${build.dbdeploy.deployfile}"
            undooutputfile="${build.dir}/${build.dbdeploy.undofile}" />

        <!-- execute the SQL - Use mysql command line to avoid trouble with large files or many statements and PDO -->
        <exec
            command="${progs.mysql} -h${db.host} -u${db.user} -p${db.pass} ${db.name} &lt; ${build.dbdeploy.deployfile}"
            dir="${build.dir}"
            checkreturn="true" />
    </target>
</project>

That’s essentially all the magic we need. Now we just need to create our database.

Writing dbdeploy delta scripts

We haven’t actually created our database, so rather than create it the traditional way, we will actually use the migrations to create the initial schema. We’ve not actually decided what our example application does yet, but seeing as most tutorials make blogs, why don’t we give that a bash. We’ll start simple, one table with three columns called post.

Field Type Comment
title VARCHAR(255) The title of our post
time_created DATETIME The time we created our post
content MEDIUMTEXT The content of our post

Dbdeploy works by creating numbered delta files. Each delta files contains simple SQL to both deploy the change and roll it back. The basic layout of a delta file is like so.

--//

-- Run SQL to do the changes

--//@UNDO

-- RUN SQL to undo the changes

--//

We are creating our initial schema, so put the following content in db/deltas/1-create_initial_schema.sql

--//

CREATE TABLE `post` (
    `title` VARCHAR(255),
    `time_created` DATETIME,
    `content` MEDIUMTEXT
);

--//@UNDO

DROP TABLE `post`;

--//

Migrating the database

We are one step away from running our first migration. To keep track of the current version of the database, dbdeploy requires a table in the database. This is the only time we will have to interact with the mysql client directly.

shell> mysql -hlocalhost -uroot -ppassword example
mysql> CREATE TABLE changelog (
  change_number BIGINT NOT NULL,
  delta_set VARCHAR(10) NOT NULL,
  start_dt TIMESTAMP NOT NULL,
  complete_dt TIMESTAMP NULL,
  applied_by VARCHAR(100) NOT NULL,
  description VARCHAR(500) NOT NULL
);
mysql> ALTER TABLE changelog ADD CONSTRAINT Pkchangelog PRIMARY KEY (change_number, delta_set);

We are now ready to run our first migration and create the initial schema for our application.

shell>cd deploy
shell>phing migrate

All being well, we now have a posts table in our database. But what about an author for our blog posts? We’ll have to add another table and a foreign key from the post table to author table. To do this we create another delta, we call this one db/deltas/2-create_author_and_link_to_post.sql

--//

CREATE TABLE `author` (
    `author_id` INT(10) unsigned auto_increment,
    `name` VARCHAR(255),
    PRIMARY KEY (`author_id`)
);

ALTER TABLE `post` ADD `author_id` INT(10) unsigned NULL;

--//@UNDO

ALTER TABLE `post` DROP `author_id`;

DROP TABLE `author`;

--//

Run our migrations again.

shell> cd deploy
shell> phing migrate

Conclusion

That’s pretty much it, you’ve seen how to create database deltas and use them to migrate your database, if you can’t be bothered to copy and paste things to try for yourself, download the example application.

There are plenty of caveats when it comes to version controlling databases, especially if you branch and merge your application code, some are detailed in the dbdeploy documentation

This tutorial is probably incomplete or wrong in plenty of ways, if you think you have something to point out, please leave your comments below

How To: Send SQL commands to a database in VIM

Thursday, March 29th, 2007

A simple way of sending SQL to your database from everyone’s favourite editor Vim, without any plugins or macros.

Firstly we need to add a custom command to our .vimrc, open it up and add the following line, where:

  • CommandName – The name of your command
  • Username – The username for this database
  • Password – The password for this database
  • Database – The name of the database
:command -range=% CommandName :<line1>,<line2>w !mysql -uUsername -pPassword Database -t

For example:

:command -range=% SendDB :<line1>,<line2>w !mysql -utest -ptest test -t

That’s all the setting up we need. As you can see, after the exclamation mark is just the regular MySQL Command line tool and various options.

Fire up vim and start editing your sql.

# vim test.sql

As an example, here’s some simple SQL.

-- Drop existing table
DROP TABLE IF EXISTS `test`;

-- Create table
CREATE TABLE IF NOT EXISTS `test` (
    `test_id` INT(11) NOT NULL auto_increment,
    `name` VARCHAR(255) NOT NULL,
    PRIMARY KEY (`test_id`)
);

-- Add our data
INSERT INTO `test`(`name`) VALUES('dave');

-- Get it back out again
SELECT * FROM `test`;

If we’re happy with what we’ve written, while in command mode, type :SendDB, or whatever you called your command and hit enter. If it works, you’ll see something like this.

~/test.sql[+][sql] unix
:SendDB
+---------+------+
| test_id | name |
+---------+------+
|       1 | dave |
+---------+------+

Press ENTER or type command to continue

You can always add to the custom command, in particular piping the output to less can be effective for larger result sets.

Ruby on Rails – First Impressions

Monday, August 28th, 2006

I’ve finally gotten around to finishing the basic design on the Broadband affiliate site project I’ve had ongoing for a while and figured it would be nice to have a backend to add/remove, de-activate all the different packages etc. So, I decided to go crazy and have a look at Ruby on Rails.

Now I’m not extremely well versed with patterns and so on, but I have a decent understanding of the MVC style architecture that seems to be popular these days and I’ve seen a few tutorials on Symfony, a PHP 5 web framework which I believe is fairly similar in nature to Rails, so I figured I’d get along okay. I feel I was pretty right, in a few hours over today and yesterday I’ve come out with a working database driven website and administration area running on Ruby on Rails.

Running Gentoo, I always try and use the portage package management tool, to be double sure on what I needed to do I had a little search on google which led me to this page, and these commands.

echo "dev-ruby/rails mysql fastcgi" >> /etc/portage/package.use
emerge -av rails
rails /path/to/app

That all went well and I was sat looking at a clean rails application. I fired up the builtin webserver, WEBrick, it worked, so I closed it again. Seeing as I use Apache on all my servers, I wanted to use it for the development aswell. I’ve never used FastCGI before, but what do you know there was an example virtual host definition in the rails README file.

  <VirtualHost *:80>
    ServerName rails
    DocumentRoot /path/application/public/
    ErrorLog /path/application/log/server.log

    <Directory /path/application/public/>
      Options ExecCGI FollowSymLinks
      AllowOverride all
      Allow from all
      Order allow,deny
    </Directory>
  </VirtualHost>

Once again, this worked a treat. I then set about creating my application, which by enlarge went along without many flaws, using a combination of the excellent Rails API, this Create a weblog in 15 minutes screencast and Rolling with Ruby on Rails as guidance. The biggest problem I had was creating initially trying to create the scaffolds. Not knowing RoR’s naming conventions, I’d foolishly named my database tables in the singular form, ie provider rather than providers. After overcoming this, I rolled on pretty nicely.

Using this page as guidance I used the login_generator to create a simple admin area, and the scaffolding stuff filled most of the admin pages for me, just a few tweaks here and there were required. The public face was even easier, basically allowing a few different ways to filter the list of broadband packages through one action, ‘list’.

As far as the language Ruby itself goes, I’ve barely learnt anything, basically because Rails does it all for me. The most complicated things I did code wise, was using a case statement to change the filtering on the public packages page and this simple function for turning bytes into a more readable form.

        def human_readable(number)
                count = 0
                while number/1024 > 1
                        number = number/1024
                        count += 1
                end

                iec = ['', 'K', 'M', 'G', 'T']
                return number.to_s + iec[count]
        end

My only gripe with this so far, is the speed. It does take forever to generate these simple pages, the built in webserver does seem to be a shade quicker, but I’d still rather use apache. I’m sure there’ll be some tweaks I can make to speed the FastCGI module up, but there’s no rush for that now.

Hopefully I’ll signup for a few affiliate programs and launch the site properly within the next few days, I don’t expect to make a fortune but it’s been a good little learning utility so far and I hope to use it to learn a few things about affiliate marketing.