Database Journal
MS SQL Oracle DB2 Access MySQL PostgreSQL Sybase PHP SQL Etc SQL Scripts & Samples Tips Database Forum

» Database Journal Home
» Database Articles
» Database Tutorials
MS Access
SQL Scripts & Samples
» Database Forum
» Slideshows
Free Newsletters:

News Via RSS Feed

Database Journal |DBA Support |SQLCourse |SQLCourse2

Featured Database Articles

SQL etc

Posted Jan 13, 2003

Moving Logic Into the Database - Page 2

By DatabaseJournal.com Staff

by Tim Perdue

Triggers and PL/pgsql

The alternative approach is to move these constraints into triggers in the database. I have messed with triggers that update counters and create rows in related tables, but this is the most I have done with PL/pgsql, the PostgreSQL programming language of choice.

There are two kinds of triggers in pl/pgsql programming, the "before" trigger and the after trigger. You use the "before" triggers if you want to modify a row of data before it is inserted into the database. That sounds like how we want to handle our start/end dates for tasks. If a user attempts to insert Task B with a start date earlier than the end date of Task A, we need to override him and push his dates back.

The other kind of trigger is the "after" trigger, which you use if you want to perform actions after your row is inserted into the database. That's how we will push back Tasks B and C if Task A is delayed.

What's really neat is that we are essentially getting recursion for "free". If Task A is updated, the trigger fires and updates Task B. The trigger for Task B is set off as well, which causes Task C to update, and so on down the line until everything is validated.

We can start by looking at the "before" trigger, which validates the start/end dates.

        dependon RECORD;
        delta INTEGER;
        --  ENFORCE START/END DATE logic
        IF NEW.start_date >= NEW.end_date THEN
        END IF;
        --        First make sure we start on or after end_date of tasks
        --        that we depend on
        FOR dependon IN SELECT * FROM project_dependon_vw
                                WHERE project_task_id=NEW.project_task_id LOOP
                --        See if the task we are dependon on
                --        ends after we are supposed to start
                IF dependon.end_date > NEW.start_date THEN
                        delta := dependon.end_date-NEW.start_date;
                        RAISE NOTICE ''Bumping Back: % Delta: % '',
                        NEW.start_date := NEW.start_date+delta;
                        NEW.end_date := NEW.end_date+delta;
                END IF;

        END LOOP;
        RETURN NEW;
' LANGUAGE 'plpgsql';

As you can see, we have logic to raise an exception if a (dimwitted) user tries to make his start date after his end date.

We also have a FOR ... IN loop which queries the tasks we are dependent on, and adjusts our start/end dates if we attempt to start before our predecessor is completed.

NEW is a reference to the row that this trigger is acting on. If this were on an UDPATE event, we would also have access to the OLD row as well. As you can see, we can reference all the fields in NEW, such as NEW.start_date, and reference all of the rows we are querying as "dependon".

Those few lines of very simple code will now guarantee that our data is always correct. If we had put this logic into PHP, it would be possible for someone to issue commands on the psql command line that could mess up our system.

SQL etc Archives

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Latest Forum Threads
SQL etc Forum
Topic By Replies Updated
MySQL rollback UAL225 0 August 21st, 09:56 PM
Complex Search Query Galway 0 May 20th, 10:04 PM
change collation at once supercain 2 May 15th, 06:18 AM
SQL Features, tools and utilities question Neomite 1 April 10th, 09:13 AM