CS240A: Winter 98. Second Project


TRIGGERS and CONSTRAINTS in ORACLE

The directory /u/class/cs240a/winter98/demo contains the various SQL queries and Oracle scripts from the book:

Kevin T. Owens, Building Intelligent Databases with Oracle PL/SQL Triggers and Stored Procedures, Prentice Hall Publisher, (2nd Edition), 1998.
Your assignement for CS240A is to perform the following tasks (refer to the README.TXT file in the DEMO directory for more detailed instructions):

Task 1. Create your sample database and execute a few SQL queries, to check that that everything is working properly.

Task 2. Draw an E-R-A diagram for the schema.

Task 3. Run the the programs d_1.sql and d_2.sql to search the data dictionary and list the existing constraints (by querying the dictionary view USER_CONS_COLUMNS). Oracle also supports the two dictionary views, USER_TRIGGERS and USER_TRIGGER_COLS for dictionary queries on triggers. Write the following two dictionary queries:

  1. For all the enabled triggers, list TRIGGER_NAME, TRIGGER_TYPE, TRIGGERING_EVENT
  2. For each table which has both constraints and triggers, list Table_Name, Constraint_Name, Trigger_Name.

Task 4. Test the triggers in trg.sql using the t*.sql scripts in demo. (The functional description of these triggers is given below.) These triggers are now implemented using PL/SQL. You must reimplement the triggers listed below under CUSTOMER INSERT, Rules 1 and 2, and CUSTOMER UPDATE, Rule 1. These are ther first three rules in trg.sql. For instance, you can proceed as follows:

A. Disable the triggers under CUSTOMER INSERT and CUSTOMER UPDATE and Reexectute Step 1 in Task 3 to show that they are in fact disabled.

B. Reimplement the three disabled triggers directly in SQL (under slightly modified name). Modify the scripts to test them.

C. With debugging facilities for active rules badly lacking, the DBMS_OUTPUT.PUT_LINE command is now the only way to trace the thread of execution for a trigger. Further modify the triggers in B to trace their excution, and re-execute the triggers. (Since it is what you do when debugging, you might in fact do C before doing B.

Task 5. Use triggers to support a temporal TSQL2-like concrete views of DEPT and EMP. These will be called EMP_Hist and DEPT_Hist and will be valid state + transaction time relations, where the valid time granularity of days--- use the day of the transaction as valid time. (Should activation of these triggers follow or precede that of other triggers?) Write simple scripts to test and display the operation of your rules.

FUNCTIONAL DESCRIPTION of CONSOLIDATED TRIGGERS

The consolidated functional trigger descriptions are

CUSTOMER INSERT

Rule 1: Raise an application error if the following is false: ACCOUNT_TYPE and ACCOUNT_ID are either both NULL or both NOT NULL. This can be achieved from evaluating the correlation values in the row trigger.

Rule 2: If the ACCOUNT_TYPE is "PR," then recursively INSERT an "RE" account for the same CUST_NAME. This recursive INSERT must be done during after-statement trigger processing. We must use a flag which blocks the INSERT trigger logic from executing during the recursive INSERT.

CUSTOMER UPDATE

Rule 1: Raise an application error if the following is false: ACCOUNT_TYPE and ACCOUNT_ID are either both NULL or both NOT NULL. This can be achieved from evaluating the correlation values in the row trigger.

Rule 3: If ACCOUNT_ID changes from NULL to NOT NULL, then decrement (retaining a positive value) the PURCHAASE_PRICE of any PURCHASE_ORDER for this customer. The update to PURCHASE_ORDER must be done in after-statement processing because PURCHASE_ORDER is a child to CUSTOMER. The row-level trigger must save the primary key of the update in a PL/SQL table.

CUSTOMER DELETE

Rule 4: This trigger depends upon the EMP_SERVICE trigger to populate a PL/SQL table with EMP_ID/CUST_ID records where SALES > 5000. It also depends upon a PURCHASE_ORDER trigger to populate a PL/SQL table with the PURCHASE_DATE for any date past 30 days. The after-statement trigger processing scans both tables to determine a constraint violation.

EMP_SERVICE_LOG DELETE

Rule 4: Raise an application error if SALES from EMP_SERVICE SALES exceeds $5000, and there exists a PURCHASE_DATE on a PURCHASE_ORDER for this customer which is past 30 days. This trigger must be able to detect a delete cascade from CUSTOMER or EMP_SERVICE. This trigger performs no operations if the delete is the result of a delete cascade. This logic can be enforced at the row level by evaluating the SALES amount from the parent EMP_SERVICE table and the PURCHASE_DATE from PURCHASE_ORDER table.

EMP_SERVICE DELETE

Rule 4: Raise an application error if the delete violates the constraint on the SALES amount and PURCHSE_DATE from PURCHASE_ORDER. The trigger must be able to detect a delete cascade. If not in a delete cascade, the trigger reads the PURCHASE_DATE from PURCHASE_ORDER for the row being deleted. If the constraint is violated an error is raised. If in a delete cascade, for any record where SALES > 5000, the row-level trigger stores the concatenated primary key in a PL/SQL table - it does not initialize the PL/SQL table and it does not enforce the rule in after-statement processing.

PURCHASE_ORDER INSERT

Rule 5: Raise an application error if WIDGET_ID references a WIDGET with STATUS = "on" and SAMPLE = "yes." This can be implemented with a row-level trigger since an INSERT into a child can read a parent.

Rule 6: If the CUSTOMER's STATE is "AK" or "HI" and QUANTITY < 100, then increment the PURCHASE_PRICE. This can be implemented at the row-level by reading the parent table CUSTIOMER for the STATE attribute and incrementing the PURCHASE_PRICE. This must be done is a BEFORE insert-row trigger since it modifies a correlation value.

PURCHASE_ORDER UPDATE

Rule 6: If the QUANTITY is changed to be greater than 100 or less than 100, then increment or decrement the PURCHASE_PRICE if the CUSTOMER's STATE is "AK" or "HI." This trigger fires only if QUANTITY is being updated. This constraint is enforced at the row level since it reads from the parent CUSTOMER table.

PURCHASE_ORDER DELETE

Rule 4: If the DELETE is the result of a delete cascade from CUSTOMER, the trigger stores the CUST_ID and the primary key in a PL/SQL table for any date past 30 days. This table is constructed for the CUSTOMER DELETE trigger enforcement of rule 4. This affects the row-level trigger only. The PL/SQL table initialization is executed by the CUSTOMER table.

Rule 7: Raise an application error if the PURCHASE_DATE is the current date, the widget STATUS = "on" and the customer has a NOT NULL ACCOUNT_ID. We ignore the enforcement if the delete is the result of a delete cascade. This constraint check is performed in row-level processing. Since we ignore enforcement during DELETE CASCADE, any mutating table error is captured and ignored.

WIDGET UPDATE

Rule 5: Raise an application error if the WIDGET is part of any PURCHASE_ORDER and the widget has the attributes: STATUS = "on" and SAMPLE = "yes." Since this requires reading the child PURCHASE_ORDER table, the rows being updated must be saved in a PL/SQL table. The after-statement processing will check for any occurrence of these widgets in PURCHASE_ORDER.