//***************************************************************************
// (c) Copyright IBM Corp. 2007 All rights reserved.
// 
// The following sample of source code ("Sample") is owned by International 
// Business Machines Corporation or one of its subsidiaries ("IBM") and is 
// copyrighted and licensed, not sold. You may use, copy, modify, and 
// distribute the Sample in any form without payment to IBM, for the purpose of 
// assisting you in the development of your applications.
// 
// The Sample code is provided to you on an "AS IS" basis, without warranty of 
// any kind. IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR 
// IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Some jurisdictions do 
// not allow for the exclusion or limitation of implied warranties, so the above 
// limitations or exclusions may not apply to you. IBM shall not be liable for 
// any damages you suffer as a result of using, copying, modifying or 
// distributing the Sample, even if IBM has been advised of the possibility of 
// such damages.
//***************************************************************************
//
// SOURCE FILE NAME: TbTrig.sqlj
//
// SAMPLE: How to use triggers
//
// SQL Statements USED:
//         CREATE TABLE
//         CREATE TRIGGER
//         DROP TABLE
//         DROP TRIGGER
//         SELECT
//         INSERT
//         UPDATE
//         DELETE
//         COMMIT
//         ROLLBACK
//
// JAVA 2 CLASSES USED:
//         Statement
//
// Classes used from Util.sqlj are:
//         Db
//         Data
//         SqljException
//
//                           
// Output will vary depending on the JDBC driver connectivity used.
//***************************************************************************
//
// For more information on the sample programs, see the README file.
//
// For information on developing Java applications see the Developing Java Applications book.
//
// For information on using SQL statements, see the SQL Reference.
//
// For the latest information on programming, compiling, and running DB2
// applications, visit the DB2 Information Center at
//     http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp
//**************************************************************************/

import java.lang.*;
import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.ref.*;

#sql iterator TbTrig_Cursor1(int, String, int, String, Integer,
                             double, Double);

class TbTrig
{
  public static void main(String argv[])
  {
    DefaultContext ctx = null;

    try
    {
      Db db = new Db(argv);

      System.out.println();
      System.out.println("THIS SAMPLE SHOWS HOW TO USE TRIGGERS.");

      // connect to the 'sample' database
      ctx = db.getDefaultContext();

      beforeInsertTriggerUse();
      afterInsertTriggerUse( ctx.getConnection() );
      beforeDeleteTriggerUse();
      beforeUpdateTriggerUse( ctx.getConnection() );
      afterUpdateTriggerUse( ctx.getConnection() );

      // disconnect from the 'sample' database
      db.disconnect();
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // main

  // helping function
  static void staffTbContentDisplay()
  {
    try
    {
      int id = 0;
      int dept = 0;
      double salary = 0.0;
      String name = null;
      String job = null;
      Integer years = new Integer(0);
      Double comm = new Double(0.0);
      TbTrig_Cursor1 c1;

      System.out.println();
      System.out.println("  SELECT * FROM staff WHERE id <= 50");
      System.out.println(
        "    ID  NAME    DEPT JOB   YEARS SALARY   COMM\n" +
        "    --- ------- ---- ----- ----- -------- --------");

      #sql c1 = {SELECT * FROM staff WHERE id <= 50};

      #sql {FETCH :c1 INTO :id, :name, :dept, :job, :years, :salary, :comm};

    while (!c1.endFetch())
    {
      System.out.print("    " + Data.format(id,3) +
                       " " + Data.format(name,7) +
                       " " + Data.format(dept,4));
      if (job != null)
      {
        System.out.print(" " + Data.format(job,5));
      }
      else
      {
        System.out.print("     -");
      }
      if (years != null)
      {
        System.out.print(" " + Data.format(years,5));
      }
      else
      {
        System.out.print("     -");
      }
      System.out.print(" " + Data.format(salary,7,2));
      if (comm != null)
      {
        System.out.print(" " + Data.format(comm,7,2));
      }
      else
      {
        System.out.print("     -");
      }
      System.out.println();

      #sql {FETCH :c1 INTO :id, :name, :dept, :job, :years, :salary, :comm};
    }
    c1.close();
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // staffTbContentDisplay

  // helping function
  static void staffStatsTbCreate(Connection con)
  {
    try
    {
      System.out.println();
      System.out.println("  CREATE TABLE staff_stats(nbemp SMALLINT)");

      #sql {CREATE TABLE staff_stats(nbemp SMALLINT)};

      System.out.println();
      System.out.println(
        "  INSERT INTO staff_stats VALUES(SELECT COUNT(*) FROM staff)");

      Statement stmt = con.createStatement();
      stmt.executeUpdate(
        "INSERT INTO staff_stats VALUES(SELECT COUNT(*) FROM staff)");
      stmt.close();

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // staffStatsTbCreate

  // helping function
  static void staffStatsTbContentDisplay(Connection con)
  {
    try
    {
      System.out.println();
      System.out.println("  SELECT nbemp FROM staff_stats");
      System.out.println("    NBEMP\n" +
                         "    -----");

      Statement stmt = con.createStatement();
      ResultSet rs2 = stmt.executeQuery("SELECT * FROM staff_stats");
      rs2.next();

      System.out.println("    " + Data.format(rs2.getShort("nbemp"),5));
      rs2.close();
      stmt.close();
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // staffStatsTbContentDisplay

  // helping function
  static void staffStatsTbDrop()
  {
    try
    {
      System.out.println();
      System.out.println("  DROP TABLE staff_stats");

      #sql {DROP TABLE staff_stats};

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // staffStatsTbDrop

  // helping function
  static void salaryStatusTbCreate(Connection con)
  {
    try
    {
      System.out.println();
      System.out.println(
        "  CREATE TABLE salary_status(emp_name VARCHAR(9),\n" +
        "                             sal DECIMAL(7, 2),\n" +
        "                             status CHAR(15))");

      #sql {CREATE TABLE salary_status(emp_name VARCHAR(9),
                                       sal DECIMAL(7, 2),
                                       status CHAR(15))};

      System.out.println();
      System.out.println("  INSERT INTO salary_status\n" +
                         "    SELECT name, salary, 'Not Defined'\n" +
                         "      FROM staff\n" +
                         "      WHERE id <= 50");

      Statement stmt = con.createStatement();
      stmt.executeUpdate("INSERT INTO salary_status " +
                         "  SELECT name, salary, 'Not Defined' " +
                         "    FROM staff " +
                         "    WHERE id <= 50");

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // salaryStatusTbCreate

  // helping function
  static void salaryStatusTbContentDisplay(Connection con)
  {
    try
    {
      System.out.println();
      System.out.println("  SELECT * FROM salary_status");
      System.out.println("    EMP_NAME   SALARY   STATUS\n" +
                         "    ---------- -------- ----------------");


      Statement stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery("SELECT * FROM salary_status");

      while (rs.next())
      {
        System.out.println(
          "    " + Data.format(rs.getString("emp_name"), 10) +
          " " + Data.format(rs.getDouble("sal"), 7, 2) +
          " " + Data.format(rs.getString("status"), 15));
      }
      rs.close();
      stmt.close();
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // salaryStatusTbContentDisplay

  // helping function
  static void salaryStatusTbDrop()
  {
    try
    {
      System.out.println();
      System.out.println("  DROP TABLE salary_status");

      #sql {DROP TABLE salary_status};

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // salaryStatusTbDrop

  // helping function
  static void salaryHistoryTbCreate()
  {
    try
    {
      System.out.println();
      System.out.println(
        "  CREATE TABLE salary_history(employee_name VARCHAR(9),\n" +
        "                              salary_record DECIMAL(7, 2),\n" +
        "                              change_date DATE)");

      #sql {CREATE TABLE salary_history(employee_name VARCHAR(9),
                                        salary_record DECIMAL(7, 2),
                                        change_date DATE)};

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // salaryHistoryTbCreate

  // helping function
  static void salaryHistoryTbContentDisplay(Connection con)
  {
    try
    {
      System.out.println();
      System.out.println("  SELECT * FROM salary_history");
      System.out.println("    EMPLOYEE_NAME  SALARY_RECORD  CHANGE_DATE\n" +
                         "    -------------- -------------- -----------");

      Statement stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery("SELECT * FROM salary_history");

      while (rs.next())
      {
        System.out.println(
          "    " + Data.format(rs.getString("employee_name"),14) +
          " " + Data.format(rs.getDouble("salary_record"),13,2) +
          " " + rs.getDate("change_date"));
      }
      rs.close();
      stmt.close();
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // salaryHistoryTbContentDisplay

  // helping function
  static void salaryHistoryTbDrop()
  {
    try
    {
      System.out.println();
      System.out.println("  DROP TABLE salary_history");

      #sql {DROP TABLE salary_history};

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // salaryHistoryTbDrop

  static void beforeInsertTriggerUse()
  {
    System.out.println();
    System.out.println(
      "----------------------------------------------------------\n" +
      "USE THE SQL STATEMENTS:\n" +
      "  CREATE TRIGGER\n" +
      "  COMMIT\n" +
      "  INSERT\n" +
      "  ROLLBACK\n" +
      "  DROP TRIGGER\n" +
      "TO SHOW A 'BEFORE INSERT' TRIGGER.");

    // display the initial content of the 'staff' table
    staffTbContentDisplay();

    // create a 'BEFORE INSERT' trigger
    try
    {
      System.out.println();
      System.out.println(
        "  CREATE TRIGGER min_sal\n" +
        "    NO CASCADE BEFORE INSERT\n" +
        "    ON staff\n" +
        "    REFERENCING NEW AS newstaff\n" +
        "    FOR EACH ROW \n" +
        "    BEGIN ATOMIC\n" +
        "      SET newstaff.salary =\n" +
        "      CASE\n" +
        "        WHEN newstaff.job = 'Mgr' AND\n" +
        "             newstaff.salary < 17000.00\n" +
        "        THEN 17000.00\n" +
        "        WHEN newstaff.job = 'Sales' AND\n" +
        "             newstaff.salary < 14000.00\n" +
        "        THEN 14000.00\n" +
        "        WHEN newstaff.job = 'Clerk' AND\n" +
        "             newstaff.salary < 10000.00\n" +
        "        THEN 10000.00\n" +
        "        ELSE newstaff.salary\n" +
        "      END;\n" +
        "    END");

      #sql {CREATE TRIGGER min_sal
              NO CASCADE BEFORE INSERT
              ON staff
              REFERENCING NEW AS newstaff
              FOR EACH ROW 
              BEGIN ATOMIC
                SET newstaff.salary =
                CASE
                  WHEN newstaff.job = 'Mgr' AND
                       newstaff.salary < 17000.00
                  THEN 17000.00
                  WHEN newstaff.job = 'Sales' AND
                       newstaff.salary < 14000.00
                  THEN 14000.00
                  WHEN newstaff.job = 'Clerk' AND
                       newstaff.salary < 10000.00
                  THEN 10000.00
                  ELSE newstaff.salary
                END;
              END};

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // insert table data using values
    try
    {
      System.out.println();
      System.out.println(
        "  Invoke the statement:\n" +
        "    INSERT INTO staff(id, name, dept, job, salary)\n" +
        "      VALUES(25, 'Pearce', 38, 'Clerk', 7217.50),\n" +
        "            (35, 'Hachey', 38, 'Mgr', 21270.00),\n" +
        "            (45, 'Wagland', 38, 'Sales', 11575.00)");

      #sql {INSERT INTO staff(id, name, dept, job, salary)
              VALUES(25, 'Pearce', 38, 'Clerk', 7217.50),
                    (35, 'Hachey', 38, 'Mgr', 21270.00),
                    (45, 'Wagland', 38, 'Sales', 11575.00)};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // display the final content of the 'staff' table
    staffTbContentDisplay();

    // roll back the transaction and then drop the trigger
    try
    {
      System.out.println();
      System.out.println("  Roll back the transaction.");

      #sql {ROLLBACK};

      System.out.println();
      System.out.println("  DROP TRIGGER min_sal");

      #sql {DROP TRIGGER min_sal};

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // beforeInsertTriggerUse

  static void afterInsertTriggerUse(Connection con)
  {
    System.out.println();
    System.out.println(
      "----------------------------------------------------------\n" +
      "USE THE SQL STATEMENTS:\n" +
      "  CREATE TRIGGER\n" +
      "  COMMIT\n" +
      "  INSERT\n" +
      "  ROLLBACK\n" +
      "  DROP TRIGGER\n" +
      "TO SHOW AN 'AFTER INSERT' TRIGGER.");

    // create a table called 'staff_stats'
    staffStatsTbCreate(con);

    // display the content of the 'staff_stats' table
    staffStatsTbContentDisplay(con);

    // create an 'AFTER INSERT' trigger
    try
    {
      System.out.println();
      System.out.println("  CREATE TRIGGER new_hire\n" +
                         "    AFTER INSERT\n" +
                         "    ON staff\n" +
                         "    FOR EACH ROW \n" +
                         "    BEGIN ATOMIC\n" +
                         "      UPDATE staff_stats\n" +
                         "      SET nbemp = nbemp + 1;\n" +
                         "    END");

      Statement stmt = con.createStatement();
      stmt.executeUpdate("CREATE TRIGGER new_hire " +
                         "  AFTER INSERT " +
                         "  ON staff " +
                         "  FOR EACH ROW " +
                         "  BEGIN ATOMIC " +
                         "    UPDATE staff_stats " +
                         "    SET nbemp = nbemp + 1; " +
                         "  END");

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // insert table data using values
    try
    {
      System.out.println();
      System.out.println(
        "  Invoke the statement:\n" +
        "    INSERT INTO staff(id, name, dept, job, salary)\n" +
        "      VALUES(25, 'Pearce', 38, 'Clerk', 7217.50),\n" +
        "            (35, 'Hachey', 38, 'Mgr', 21270.00),\n" +
        "            (45, 'Wagland', 38, 'Sales', 11575.00)");

      #sql {INSERT INTO staff(id, name, dept, job, salary)
              VALUES(25, 'Pearce', 38, 'Clerk', 7217.50),
                    (35, 'Hachey', 38, 'Mgr', 21270.00),
                    (45, 'Wagland', 38, 'Sales', 11575.00)};

      // display the content of the 'staff_stats' table
      staffStatsTbContentDisplay(con);

      // roll back the transaction
      System.out.println();
      System.out.println("  Roll back the transaction.");

      #sql {ROLLBACK};

      // drop the trigger
      System.out.println();
      System.out.println("  DROP TRIGGER new_hire");

      Statement stmt = con.createStatement();
      stmt.executeUpdate("DROP TRIGGER new_hire");
      stmt.close();

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // drop the 'staff_stats' table
    staffStatsTbDrop();

  } // afterInsertTriggerUse

  static void beforeDeleteTriggerUse()
  {
    String sqlstate;
    String sqlerrmsg;

    System.out.println();
    System.out.println(
      "----------------------------------------------------------\n" +
      "USE THE SQL STATEMENTS:\n" +
      "  CREATE TRIGGER\n" +
      "  COMMIT\n" +
      "  DELETE\n" +
      "  ROLLBACK\n" +
      "  DROP TRIGGER\n" +
      "TO SHOW A 'BEFORE DELETE' TRIGGER.");

    // display the initial content of the 'staff' table
    staffTbContentDisplay();

    // create a 'BEFORE DELETE' trigger
    try
    {
      System.out.println();
      System.out.println("  CREATE TRIGGER do_not_delete_sales\n" +
                         "    NO CASCADE BEFORE DELETE\n" +
                         "    ON staff\n" +
                         "    REFERENCING OLD AS oldstaff\n" +
                         "    FOR EACH ROW \n" +
                         "    WHEN (oldstaff.job = 'Sales')\n" +
                         "    BEGIN ATOMIC\n" +
                         "      SIGNAL SQLSTATE '75000' " +
                         "('Sales cannot be deleted now.');\n" +
                         "    END");

      #sql {CREATE TRIGGER do_not_delete_sales
              NO CASCADE BEFORE DELETE
              ON staff
              REFERENCING OLD AS oldstaff
              FOR EACH ROW 
              WHEN(oldstaff.job = 'Sales')
              BEGIN ATOMIC
                SIGNAL SQLSTATE '75000' ('Sales cannot be deleted now.');
              END};

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // delete data from the 'staff' table
    try
    {
      System.out.println();
      System.out.println("  Invoke the statement:\n" +
                         "    DELETE FROM staff WHERE id <= 50");

      #sql {DELETE FROM staff WHERE id <= 50};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handleExpectedErr();
    }
    // display the final content of the 'staff' table
    staffTbContentDisplay();

    // roll back the transaction and then drop the trigger
    try
    {
      System.out.println();
      System.out.println("  Roll back the transaction.");

      #sql {ROLLBACK};

      System.out.println();
      System.out.println("  DROP TRIGGER do_not_delete_sales");

      #sql {DROP TRIGGER do_not_delete_sales};

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }
  } // beforeDeleteTriggerUse

  static void beforeUpdateTriggerUse(Connection con)
  {
    System.out.println();
    System.out.println(
      "----------------------------------------------------------\n" +
      "USE THE SQL STATEMENTS:\n" +
      "  CREATE TRIGGER\n" +
      "  COMMIT\n" +
      "  UPDATE\n" +
      "  ROLLBACK\n" +
      "  DROP TRIGGER\n" +
      "TO SHOW A 'BEFORE UPDATE' TRIGGER.");

    // create a table called salary_status
    salaryStatusTbCreate(con);

    // display the content of the 'salary_status' table
    salaryStatusTbContentDisplay(con);

    // create a 'BEFORE UPDATE' trigger
    try
    {
      System.out.println();
      System.out.println(
        "  CREATE TRIGGER salary_status\n" +
        "    NO CASCADE BEFORE UPDATE OF sal\n" +
        "    ON salary_status\n" +
        "    REFERENCING NEW AS new OLD AS old\n" +
        "    FOR EACH ROW \n" +
        "    BEGIN ATOMIC\n" +
        "      SET new.status =\n" +
        "      CASE\n" +
        "        WHEN new.sal < old.sal\n" +
        "        THEN 'Decreasing'\n" +
        "        WHEN new.sal > old.sal\n" +
        "        THEN 'Increasing'\n" +
        "      END;\n" +
        "    END");

      Statement stmt = con.createStatement();
      stmt.executeUpdate("CREATE TRIGGER sal_status " +
                         "  NO CASCADE BEFORE UPDATE OF sal " +
                         "  ON salary_status " +
                         "  REFERENCING NEW AS new OLD AS old " +
                         "  FOR EACH ROW " +
                         "  BEGIN ATOMIC " +
                         "    SET new.status = " +
                         "    CASE " +
                         "      WHEN new.sal < old.sal " +
                         "      THEN 'Decreasing' " +
                         "      WHEN new.sal > old.sal " +
                         "      THEN 'Increasing' " +
                         "    END; " +
                         "  END");

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // update data in table 'salary_status'
    try
    {
      System.out.println();
      System.out.println("  Invoke the statement:\n" +
                         "    UPDATE salary_status SET sal = 18000.00");

      Statement stmt = con.createStatement();
      stmt.executeUpdate("UPDATE salary_status SET sal = 18000.00");
      stmt.close();
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // display the content of the 'salary_status' table
    salaryStatusTbContentDisplay(con);

    // roll back the transaction
    try
    {
      System.out.println();
      System.out.println("  Roll back the transaction.");

      #sql {ROLLBACK};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // drop the trigger
    try
    {
      System.out.println();
      System.out.println("  DROP TRIGGER sal_status");

      Statement stmt = con.createStatement();
      stmt.executeUpdate("DROP TRIGGER sal_status");

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // drop salary_status table
    salaryStatusTbDrop();

  } // beforeUpdateTriggerUse

  static void afterUpdateTriggerUse(Connection con)
  {
    System.out.println();
    System.out.println(
      "----------------------------------------------------------\n" +
      "USE THE SQL STATEMENTS:\n" +
      "  CREATE TRIGGER\n" +
      "  COMMIT\n" +
      "  UPDATE\n" +
      "  DROP TRIGGER\n" +
      "TO SHOW AN 'AFTER UPDATE' TRIGGER.");

    // create a table called 'salary_history'
    salaryHistoryTbCreate();

    // display the content of the 'salary_history' table
    salaryHistoryTbContentDisplay(con);

    try
    {
      System.out.println();
      System.out.println("  CREATE TRIGGER sal_history\n" +
                         "    AFTER UPDATE OF salary\n" +
                         "    ON staff\n" +
                         "    REFERENCING NEW AS newstaff\n" +
                         "    FOR EACH ROW \n" +
                         "    BEGIN ATOMIC\n" +
                         "      INSERT INTO salary_history\n" +
                         "        VALUES(newstaff.name,\n" +
                         "               newstaff.salary,\n" +
                         "               CURRENT DATE);\n" +
                         "    END");

      Statement stmt = con.createStatement();
      stmt.executeUpdate("CREATE TRIGGER sal_history " +
                         "  AFTER UPDATE OF salary " +
                         "  ON staff " +
                         "  REFERENCING NEW AS newstaff " +
                         "  FOR EACH ROW " +
                         "  BEGIN ATOMIC " +
                         "    INSERT INTO salary_history " +
                         "      VALUES(newstaff.name, " +
                         "             newstaff.salary, " +
                         "             CURRENT DATE); " +
                         "  END");

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // update table data
    try
    {
      System.out.println();
      System.out.println(
        "  Invoke the statement:\n" +
        "    UPDATE staff SET salary = 20000.00 WHERE name = 'Sanders'");

      #sql {UPDATE staff SET salary = 20000.00 WHERE name = 'Sanders'};

      System.out.println();
      System.out.println(
        "  Invoke the statement:\n" +
        "    UPDATE staff SET salary = 21000.00 WHERE name = 'Sanders'");

      #sql {UPDATE staff SET salary = 21000.00 WHERE name = 'Sanders'};

      System.out.println();
      System.out.println(
        "  Invoke the statement:\n" +
        "    UPDATE staff SET salary = 23000.00 WHERE name = 'Sanders'");

      #sql {UPDATE staff SET salary = 23000.00 WHERE name = 'Sanders'};

      System.out.println();
      System.out.println(
        "  Invoke the statement:\n" +
        "    UPDATE staff SET salary = 20000.00 WHERE name = 'Hanes'");

      #sql {UPDATE staff SET salary = 20000.00 WHERE name = 'Hanes'};

      System.out.println();
      System.out.println(
        "  Invoke the statement:\n" +
        "    UPDATE staff SET salary = 21000.00 WHERE name = 'Hanes'");

      #sql {UPDATE staff SET salary = 21000.00 WHERE name = 'Hanes'};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // display the content of the 'salary_history' table
    salaryHistoryTbContentDisplay(con);

    // roll back the transaction
    try
    {
      System.out.println();
      System.out.println("  Roll back the transaction.");

      #sql {ROLLBACK};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // drop the trigger
    try
    {
      System.out.println();
      System.out.println("  DROP TRIGGER sal_history");

      Statement stmt = con.createStatement();
      stmt.execute("DROP TRIGGER sal_history");

      System.out.println();
      System.out.println("  COMMIT");

      #sql {COMMIT};
    }
    catch (Exception e)
    {
      SqljException sqljExc = new SqljException(e);
      sqljExc.handle();
    }

    // drop the 'salary_history' table
    salaryHistoryTbDrop();

  } // afterUpdateTriggerUse
} // TbTrig