In this occasion, we have a PHP/Firebird application. We had to backup the database and the code (which includes PHP, HTML, CSS, Javascript files as well as user documents uploaded into a folder).
We have created a folder /mybackup/ and created a bash script backup.sh to do the following, using nano command line editor. We will always have 2 compressed gz files, remove the old ones. Backup the database, compress it. Backup the code folder, compress it. Rewind the tape. Then, copy into the tape. We are expecting the client to eject the tape and insert another one everyday, Monday to Friday.
#!/bin/bash rm -f *.gz /opt/firebird/bin/gbak -t -user sysdba -password "mypassword" localhost:mydb /mybackup/mydb.fbk gzip mydb.fbk tar -cpf mycode.tar /var/www/html gzip mycode.tar mt -f /dev/st0 rewind tar -cpf /dev/st0 *.gz
(mydb is an alias pointing to a FDB database file defined in Firebird aliases.conf)
Using Webmin, my favourite online system administration tool for Linux, I’ve created a cron job to run /mybackup/backup.sh at required intervals.
Make sure that the user account that runs the commands has the execute and write permissions where needed.
Install mt, if your system has not got it already.
After years of torturing their SQL Server users, Microsoft provided a “better” way of paging records in version 2005, and it is a weird one! The following example is from their website, an article about ROW_NUMBER (Transact-SQL).
USE AdventureWorks; GO WITH OrderedOrders AS ( SELECT SalesOrderID, OrderDate, ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber' FROM Sales.SalesOrderHeader ) SELECT * FROM OrderedOrders WHERE RowNumber BETWEEN 50 AND 60;
It is simply unacceptable, non-standard, impractical! By the way, you can not use column numbers (e.g. ORDER BY 1, 2 DESC); you must specify column names.
As usual, Microsoft programmers do not “think” and do not expect to work on millions of records, they simply say: “Buy more RAM, faster CPU, a better machine!” etc. Upgrade, upgrade, upgrade! They still do not understand that they will not be able to replace international standards organisation or something like that.
Unfortunately, we can not force our users not to ask for all the records; if they want to see them, we need to provide the facility, and show the records page by page.
Possibly, MySQL developers thought about the speed of the database engine while they were developing it, and LIMIT clause was a part of it since middle ages!
SELECT SalesOrderID, OrderDate FROM SalesOrderHeader ORDER BY OrderDate LIMIT 10 OFFSET 49
Similarly, Firebird SQL has a very simple clause to get a page of records like this, using FIRST m SKIP n syntax:
SELECT FIRST 10 SKIP 49 SalesOrderID, OrderDate FROM SalesOrderHeader ORDER BY OrderDate
PostgreSQL works same as MySQL:
SELECT SalesOrderID, OrderDate FROM SalesOrderHeader ORDER BY OrderDate LIMIT 10 OFFSET 49
Although Oracle SQL has a function (similar to MS SQL Server 2005) called ROW_NUMBER(), they also offer a pseudocolumn called ROWNUM to achieve the same:
SELECT SalesOrderID, OrderDate FROM SalesOrderHeader WHERE ROWNUM BETWEEN 50 AND 60 ORDER BY OrderDate
Note that this method requires modification of the criteria (WHERE clause) of the original query. I do not want to comment on who is mimicing who, but it is known that Microsoft do it more often, or simply buy the rival company owning a popular software application.
You can easily get lost inside the terrible documentation of IBM for DB2 database: it supports the approach using ROW_NUMBER() function.
My favourite database management systems are: Firebird, MySQL and Oracle. Sometimes you are not given any options and have to use what is available on the application server, like MS SQL Server 2000/2005 on a Windows server, MySQL 5 usually on a Linux machine.
Ingredients for our web application are Apache HTTP Server 2.2, PHP 5.2, Firebird 2.1and Oracle 10g Express Edition.
Like in any IT project, not everything goes according to plan and there are so many pitfalls; some of which are:
- Repositories
- Linux Firewall
- SE Linux Permissions
Using the package manager (Yum) to add, remove and upgrade applications is quite straight forward. You can install and uninstall applications fairly easily by just ticking and unticking a few boxes and APPLYYY!. Yum will take care of the applications and libraries that installed application requires (dependency tree).
Installing CentOS 5.3 with standard web server tools should be all right.
Although the default packages allows you to install earlier versions of Apache HTTPd 2.2.3 and PHP 5.1.6, when the latest are Apache HTTPd 2.2.12 and PHP 5.3, you think it should be all right, but no, unfortunately!
First, we need to install Firebird: luckily you can download the RPM file and double click on it!
On my system, it is installed on /opt/firebird/ by default. So, run gsec as root to manage user accounts as usual:
/opt/firebird/bin/gsec
Unfortunately, there are not many online tools to administer Firebird database; have a look at ibWebAdmin.
And for Oracle, just download the RPM file, and intallation is easy. This one is the 10g R2 Express Edition (Universal), free to use like MS SQL Server Express.
Run the following command to configure and set a password:
/etc/init.d/oracle-xe configure
Then, you can manage the Oracle system within the browser:
http://localhost:8080/apex
First problem is the firewall: if you want to manage Oracle from another PC on your network, allow connections on the port 8080. If you need to access Firebird only locally, you do not need to open port 3050.
The real nitty gritty stuff come when you need particular libraries, modules and functions in PHP: to connect to Oracle and Firebird, for instance.
Normally, you would run Yum command to add these functionalities:
yum install php-firebirdBut, it will not find them in the default repositories. This did the trick for me:
yum install php-interbase --enablerepo epel-testing
To be continued..
(as promised /wp/index.php/2009/12/setting-up-a-web-application-on-centos-continued/)
Firebird SQL Server has always been a “proper” database system since it forked from Borland’s famous Interbase. I just love it!
In some big database applications, I found that the developers preferred to duplicate a set of tables for probably performance reasons.
For example, in most accounting databases, there is a notion of company so that you can create multiple companies and manage its clients, suppliers, transactions etc. separately. Also, for critical changes in the way you do business or because of the changes in the whole country, you can leave it aside as historical data, and create a new company to start afresh.
So, if we have tables for client and supplier accounts, invoices, invoice details (items, products) and so on and so forth, they are duplicated for each company. For instance, the table “TBL_ACCOUNT_AB” is for company ABC (just a reference code for your company) and the table “TBL_ACCOUNT_XY” is for another company (XYZ). Likewise, you may have 50 tables, if you have 5 companies and 10 tables in your set.
You may say, I thought as well: why do we not duplicate the whole database? Well, we may not need the whole database to be duplicated and it has other implications, such as managing the user list, etc.
Here comes the power of Firebird:

Let’s define a simple set of tables for company ABC:
CREATE TABLE TBL_ACCOUNT_AB ( ACC_ID INTEGER NOT NULL , ACC_NAME VARCHAR(50) , CONSTRAINT PK_ACCOUNT_AB PRIMARY KEY (ACC_ID) );
CREATE TABLE TBL_INVOICE_AB ( ACC_ID INTEGER NOT NULL , INV_ID INTEGER NOT NULL , OTHER_DATA VARCHAR(50) , CONSTRAINT PK_INVOICE_AB PRIMARY KEY (INV_ID) , CONSTRAINT FK_INVOICE_AB FOREIGN KEY (ACC_ID) REFERENCES TBL_ACCOUNT_AB (ACC_ID) );
..and duplicate these for company XYZ:
CREATE TABLE TBL_ACCOUNT_XY ( ACC_ID INTEGER NOT NULL , ACC_NAME VARCHAR(50) , CONSTRAINT PK_ACCOUNT_XY PRIMARY KEY (ACC_ID) ); CREATE TABLE TBL_INVOICE_XY ( ACC_ID INTEGER NOT NULL , INV_ID INTEGER NOT NULL , OTHER_DATA VARCHAR(50) , CONSTRAINT PK_INVOICE_XY PRIMARY KEY (INV_ID) , CONSTRAINT FK_INVOICE_XY FOREIGN KEY (ACC_ID) REFERENCES TBL_ACCOUNT_XY (ACC_ID) );
To track the current company record, let’s have a simple parameter/settings table:
CREATE TABLE TBL_SETTING( ID INTEGER DEFAULT 0 NOT NULL /* Primary Key, always=0 */ , CMP VARCHAR(2) DEFAULT 'AB' /* Company Abbreviation */ , CONSTRAINT PK_SETTING PRIMARY KEY (ID) );
It’s very simple to create a stored procedure to get data from our tables. But, on this one, the trick is automatically switch between the sets and get data from that set. Here are 2 samples:
1. For the main table:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | SET TERM ^ ; CREATE PROCEDURE SP_ACCOUNT RETURNS ( ACC_ID INTEGER, NAME VARCHAR(50)) AS DECLARE VARIABLE CMP VARCHAR(2); DECLARE VARIABLE SQL VARCHAR(255); BEGIN SELECT CMP FROM "TBL_PARAM" INTO :CMP; SQL = 'SELECT ACC_ID, NAME FROM TBL_ACCOUNT_' || CMP; FOR EXECUTE STATEMENT SQL INTO :ACC_ID, :NAME DO SUSPEND; END ^ SET TERM ; ^ |
2. For the subtable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | SET TERM ^ ; CREATE PROCEDURE SP_INVOICE RETURNS ( ACC_ID INTEGER, INV_ID INTEGER, OTHER_DATA VARCHAR(50) ) AS DECLARE VARIABLE CMP VARCHAR(2); DECLARE VARIABLE SQL VARCHAR(255); BEGIN SELECT CMP FROM TBL_PARAM INTO :CMP; SQL = 'SELECT ACC_ID, INV_ID, OTHER_DATA from TBL_INVOICE_' || CMP; FOR EXECUTE STATEMENT SQL INTO :ACC_ID, :INV_ID, :OTHER_DATA DO SUSPEND; END ^ SET TERM ; ^ |
Now, all this is for not duplicating the effort whenever we need these 2 tables:
WRITE IT ONCE, REUSE IT!
Another excellent feature of Firebird is to be able to use stored procedures in SELECT statements:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | SET TERM ^ ; CREATE PROCEDURE SP_ACCOUNT_INVOICE ( CRIT VARCHAR(50) ) RETURNS ( ACC_ID INTEGER, NAME VARCHAR(50), INV_ID INTEGER, OTHER_DATA VARCHAR(50) ) AS BEGIN FOR EXECUTE STATEMENT 'SELECT A.ID, A.NAME, I.INV_ID, I.OTHER_DATA FROM SP_ACCOUNT A INNER JOIN SP_INVOICE I ON A.ACC_ID = I.ACC_ID WHERE A.NAME LIKE ''%' || :CRIT || '%'' ' INTO :ACC_ID, :NAME, :INV_ID, :OTHER_DATA DO SUSPEND; END ^ SET TERM ; ^ |
Can you do this in M$ SQL Server? NO!
You have to spend so much time to get the similar effect. If you want to reuse your stored procedures, you must create FUNCTIONS (returning tables) in M$ SQL, in which you can NOT use dynamic SQL (using EXEC or similar command). This means you have to stick to stored procedures ALL the time and you must duplicate what we did on SP_TEST whenever you need.
For example, you may want to create 10 reports based on your client accounts table. This means: you must write 10 stored procedures and repeat the same block of statements to get the account details!
Sometimes, in M$ SQL, I use VIEWS and I must fix the table names:
CREATE VIEW VW_TEST AS SELECT * FROM TBL_TEST_AB
and when the change comes, it IS a waste of time to go through all the VIEWS and recompile them with the new extension:
CREATE VIEW VW_TEST AS SELECT * FROM TBL_TEST_XY
THIS IS TERRIBLE!

Use Firebird SQL Server, if you have the luxury to choose among many database systems.
http://www.firebirdsql.org/

If you want to deal with the COMPLEXITY, try PostgreSQL Server.
http://www.postgresql.org/
MySQL is trying to become a “proper” database system on VERSION 5 (For God’s sake!).
http://www.mysql.com/
If you fancy a POSH database system, try Oracle. It has express version available for free; check the licence details.
http://www.oracle.com/
If you are walking on the road, bricks of which are laid by Microsoft, I need not say anything; you are already using M$ SQL Server 200x.
http://www.microsoft.com/sql/
..clearly, the links show which one is profit-seeking company, which one is non-profit organisation :p
