+ All Categories
Home > Documents > Practice PLSQL

Practice PLSQL

Date post: 02-Oct-2015
Category:
Upload: eugen
View: 120 times
Download: 7 times
Share this document with a friend
Description:
begin PLSQL programing
60
Practice 1: Working with Procedure Builder This practice gives you exposure to the Procedure Builders capability of creating client-side and server- side procedures, accessing server-side objects, and resolving basic compile errors. Assumptions You have Procedure Builder installed on your workstation. You have access to a schema on an Oracle database. You have the privileges needed to create procedures. You have an EMP table. Instructions 1. 1. Create a procedure called MY_LOOP in Procedure Builder that will print the numbers 1 through to 10; each on its own line. Run the procedure in the PL/SQL Interpreter. Open Procedure Builder. Click “Program Units” in the Object Navigator. Click the “+” button on the side toolbar (or File > New > Procedure on the top menu). Then enter the following code in the Program Unit Editor. PROCEDURE my_loop IS BEGIN FOR i IN 1..10 LOOP TEXT_IO.PUT_LINE(i); END LOOP; END; Compile the Procedure by clicking the
Transcript

Practice 1: Working with Procedure Builder

This practice gives you exposure to the Procedure Builders capability of creating client-side and server-side procedures, accessing server-side objects, and resolving basic compile errors.Assumptions You have Procedure Builder installed on your workstation. You have access to a schema on an Oracle database. You have the privileges needed to create procedures. You have an EMP table. Instructions1. 1. Create a procedure called MY_LOOP in Procedure Builder that will print the numbers 1 through to 10; each on its own line. Run the procedure in the PL/SQL Interpreter. Open Procedure Builder. Click Program Units in the Object Navigator. Click the + button on the side toolbar (or File > New > Procedure on the top menu). Then enter the following code in the Program Unit Editor.

PROCEDURE my_loop IS BEGIN FOR i IN 1..10 LOOP TEXT_IO.PUT_LINE(i); END LOOP; END; Compile the Procedure by clicking the Compile button. Navigate to the PL/SQL Interpreter dialog window. Enter my_loop;

2. Using Procedure Builder, add a new department to the DEPT table. Verify the addition and then ROLLBACK; Open Procedure Builder. Connect to the database by either clicking File > Connect, or double-clicking Database Objects in the Object Navigator. Log in. In the PL/SQL Interpreter, enter:PL/SQL> INSERT INTO DEPT +> (deptno, dname, loc) +> VALUES +> (50,'EDUCATION','MINNEAPOLIS');Verify the change by typing PL/SQL> SELECT * FROM dept;DEPTNO DNAME LOC ------ -------------- ------------- 10 ACCOUNTING NEW YORK

20 RESEARCH DALLAS 30 SALES CHICAGO 40 OPERATIONS BOSTON 50 EDUCATION MINNEAPOLIS Then enter ROLLBACK to undo the addition.

3. Implement (copy) the My_loop procedure on the server Assuming you still have Procedure Builder running and are still logged on, Expand (click +) the Database Objects node in the Object Navigator.

Find your schema and expand that node.

Notice the Stored Program Units node.

Click the MY_LOOP procedure in the Program Units node and drag it to the Stored Program Units node.

Delete the client side MY_LOOP procedure.

Notice the * beside your remaining server-side MY_LOOP. It did not recompile successfully on the server!

Open the Stored Program Unit editor (by double-clicking on the icon. Notice the error. Change TEXT_IO to DBMS_OUTPUT and recompile.

This completes the practice.Practice 4: Creating Procedures

The practice gives you practical exposure to creating and dropping procedures with and without parameters. S You may choose to complete this lab in SQL*Plus or in Procedure Builder. The solutions are described in SQL*Plus. Assumptions You have Procedure Builder installed on your workstations (if you want to do the practice in Procedure Builder). You have access to SQL*Plus (if you want to do the practice in SQL*Plus). You have access to a schema on an Oracle database. You have the privileges needed to create procedures. You have EMP and PRODUCT tables. Instructions2. 1. Create a Procedure that display Hello World on the screen. Execute it and then delete the procedure.Open SQL*Plus and log in to your practice schema.SQL> SET SERVEROUTPUT ONSQL> CREATE OR REPLACE PROCEDURE hello_world 2 IS 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE('Hello World!'); 5 END; 6 /Procedure created.SQL> EXEC hello_world;Hello World!PL/SQL procedure successfully completed.SQL> DROP PROCEDURE hello_world;Procedure dropped.

3. 2. Create a procedure called ADD_PROD to insert a new product into the PRODUCT table. The procedure receives a product number and a product description. If a product with that product number exists, display a meaningful message on the screen and then generate a server error (hint: Use RAISE_APPLICATION_ERROR to generate the server error).Test your new procedure with the following statements.SQL> EXEC ADD_PROD(1,'Picture Frames') PL/SQL procedure successfully completed.SQL> EXEC ADD_PROD(100860,'Picture Frames') Product 100860 already exists!BEGIN ADD_PROD(100860,'Picture Frames'); END;*ERROR at line 1:ORA-20001: Invalid Product IDORA-06512: at "OLN.ADD_PROD", line 12ORA-06512: at line 1

SQL> CREATE OR REPLACE PROCEDURE add_prod 2 (i_prodid IN product.prodid%TYPE, 3 i_descrip IN product.descrip%TYPE) 4 IS 5 BEGIN 6 INSERT INTO product (prodid, descrip) 7 VALUES (i_prodid, i_descrip); 8 EXCEPTION 9 WHEN DUP_VAL_ON_INDEX THEN 10 DBMS_OUTPUT.PUT_LINE 11 ('Product ' || i_prodid || 12 ' already exists!'); 13 RAISE_APPLICATION_ERROR 14 (-20001,'Invalid Product ID'); 15 END add_prod; 16 /Procedure created.

4. 3. Create a procedure called DEL_PROD to delete a product from the PRODUCT table given a product IDif the product does not exist. Display a message and then generate a server error.Test your new procedure with the following statements.SQL> EXEC del_prod(1);PL/SQL procedure successfully completed.SQL> EXEC del_prod(1);1 does not exist!BEGIN del_prod(1); END;*ERROR at line 1:ORA-20203: No products deleted.ORA-06512: at "OLN.DEL_PROD", line 9ORA-06512: at line 1CREATE OR REPLACE PROCEDURE del_prod (i_prodid IN product.prodid%TYPE)ISBEGIN DELETE FROM product WHERE prodid = i_prodid; IF SQL%NOTFOUND THEN DBMS_OUTPUT.PUT_LINE (i_prodid || ' does not exist!'); RAISE_APPLICATION_ERROR (-20203,'No products deleted.'); END IF;END DEL_PROD;/Procedure created.

5. 4. Create a procedure called QUERY_EMP to query the EMP table. The employee number is passed in and the job title is returned. A salary accumulator bind variable is passed in. The salary of the particular employee is added to it and the new amount is passed out.If the employee does not exist, display an error message and then generate a server error.Test your new procedure with the following statements.SQL> VARIABLE job VARCHAR2(100)SQL> VARIABLE sal NUMBERSQL> EXEC :sal := 0PL/SQL procedure successfully completed.SQL> EXEC query_emp(7698,:sal,:job)PL/SQL procedure successfully completed.SQL> PRINT jobJOB---------------------------------------------------MANAGERSQL> PRINT sal SAL---------- 2850SQL> EXEC query_emp(7369,:sal,:job)PL/SQL procedure successfully completed.SQL> PRINT jobJOB---------------------------------------------------CLERKSQL> PRINT sal SAL---------- 3650SQL> EXEC query_emp(9999,:sal,:job)Employee 9999 does not exist!BEGIN query_emp(9999,:sal,:job); END;*ERROR at line 1:ORA-20001: Bad employee numberORA-06512: at "OLN.QUERY_EMP", line 18ORA-06512: at line 1SQL> CREATE OR REPLACE PROCEDURE query_emp 2 (i_empno IN emp.empno%TYPE, 3 io_sal IN OUT emp.sal%TYPE, 4 o_job OUT emp.job%TYPE) 5 IS 6 v_sal emp.sal%TYPE; 7 BEGIN 8 SELECT sal, job 9 INTO V_sal, o_job 10 FROM emp 11 WHERE empno = i_empno; 12 io_sal := v_sal + io_sal; 13 EXCEPTION 14 WHEN NO_DATA_FOUND THEN 15 DBMS_OUTPUT.PUT_LINE 16 ('Employee ' || i_empno || 17 ' does not exist!'); 18 RAISE_APPLICATION_ERROR 19 (-20001,'Bad employee number'); 20 END query_emp; 21 /Procedure created.

This completes the practice.( Oracle Corporation, 2002Practice 6: Creating Functions

In this practice, you create and drop server-side functions. You use these functions as part of PL/SQL statements and SQL statements.

The solutions aredescribed in SQL*Plus. Assumptions You have Procedure Builder installed on your workstation (if you want to do the practice in Procedure Builder). You have access to SQL*Plus (if you want to do the practice in SQL*Plus). You have access to a schema on an Oracle database. You have the privileges needed to create procedures and functions. You have EMP, DEPT, and PRODUCT tables. Instructions6. 1. Create a function called Q_PROD that, given a product ID, returns the product description. If the product ID is invalid, the function will return Invalid Product Number. Test your function with the following PL/SQL and SQL statements.SQL> VAR description VARCHAR2(100)SQL> EXEC :description := q_prod(100860)PL/SQL procedure successfully completed.SQL> PRINT descriptionDESCRIPTION-------------------------------------------ACE TENNIS RACKET ISQL> EXEC :description := q_prod(0)PL/SQL procedure successfully completed.SQL> PRINT descriptionDESCRIPTION-------------------------------------------Invalid Product NumberSQL> SELECT ordid, q_prod(prodid) as descrip, qty 2 FROM item 3 WHERE ordid = 6104 4 / ORDID DESCRIP QTY---------- ------------------------------ ---------- 610 ACE TENNIS RACKET I 1 610 ACE TENNIS BALLS-3 PACK 3 610 ACE TENNIS NET 1SQL> CREATE OR REPLACE FUNCTION q_prod 2 (v_prodid IN product.prodid%TYPE) 3 RETURN VARCHAR2 4 IS 5 v_descrip product.descrip%TYPE; 6 BEGIN 7 SELECT descrip 8 INTO v_descrip 9 FROM product 10 WHERE prodid = v_prodid; 11 RETURN (v_descrip); 12 EXCEPTION 13 WHEN NO_DATA_FOUND THEN 14 RETURN 'Invalid Product Number'; 15 END q_prod; 16 /Function created.

7. 2. Create a function called get_sal that returns the salary of an employee given the employee number. If no employee number is given, it will return the summation of the salaries from the EMP table. If an invalid employee number was given, it will return NULL. Test your function with the following statements.SQL> VAR TOTAL_SAL NUMBERSQL> EXECUTE :total_sal := get_sal(7839)PL/SQL procedure successfully completed.SQL> PRINT TOTAL_SAL TOTAL_SAL---------- 5000SQL> EXECUTE :total_sal := get_sal;PL/SQL procedure successfully completed.SQL> PRINT TOTAL_SAL TOTAL_SAL---------- 29025SQL> EXECUTE :total_sal := get_sal(9999)PL/SQL procedure successfully completed.SQL> PRINT TOTAL_SALTOTAL_SAL----------SQL> CREATE OR REPLACE FUNCTION get_sal 2 (i_empno emp.empno%TYPE DEFAULT NULL) 3 RETURN NUMBER 4 IS 5 v_total_sal NUMBER; 6 BEGIN 7 IF i_empno IS NULL THEN 8 SELECT SUM(SAL) 9 INTO v_total_sal 10 FROM emp; 11 ELSE 12 SELECT sal 13 INTO v_total_sal 14 FROM emp 15 WHERE empno = i_empno; 16 END IF; 17 RETURN v_total_sal; 18 EXCEPTION 19 WHEN NO_DATA_FOUND THEN 20 RETURN NULL; 21 END get_sal; 22 /Function created.

This completes the practice.( Oracle Corporation, 2002Practice 8: Create Packages

In this practice, you create and drop package specifications and bodies on the server. You gain experience with PRIVATE and PUBLIC program units within the package. The solutions are described in SQL*Plus.Assumptions You have Procedure Builder installed on your workstation (if you wish to do the practice in Procedure Builder). You have access to SQL*Plus (if you wish to do the practice in SQL*Plus). You have access to a schema on an Oracle database. You have the privileges needed to create packages. You understand procedures and functions. You have EMP, DEPT, and PRODUCT tables. Instructions8. 1. You have created several stand-alone procedures and a function, and you are now convinced that you would achieve better performance if you put them into a package. Create a package (PROD_PACK) that has the ADD_PROD, UPD_PROD, DEL_PROD procedures and the Q_PROD function. Make the Q_PROD function rivate and, for now, declare that function first within the body. (You get a compile error if you dont.)Test your package with the following statements.SQL> SET SERVEROUTPUT ONSQL> EXEC prod_pack.add_prod(1,'Orange Slice');PL/SQL procedure successfully completed.SQL> EXEC prod_pack.upd_prod(1,'Pepsi One');1 was Orange Slice1 updated to Pepsi OnePL/SQL procedure successfully completed.SQL> EXEC prod_pack.del_prod(1);PL/SQL procedure successfully completed.SQL> EXEC prod_pack.del_prod(1);1 does not exist!BEGIN prod_pack.del_prod(1); END;*ERROR at line 1:ORA-20203: No products deleted.ORA-06512: at "OLN.PROD_PACK", line 67ORA-06512: at line 1The code for these units follows.PROCEDURE add_prod (i_prodid IN product.prodid%TYPE, i_descrip IN product.descrip%TYPE)ISBEGIN INSERT INTO product (prodid, descrip) VALUES (i_prodid, i_descrip);EXCEPTION WHEN DUP_VAL_ON_INDEX THEN DBMS_OUTPUT.PUT_LINE ('Product ' || i_prodid || ' already exists!'); RAISE_APPLICATION_ERROR (-20001,'Invalid Product ID');END add_prod;PROCEDURE upd_prod (i_prodid IN product.prodid%TYPE, i_descrip IN product.descrip%TYPE)ISBEGIN DBMS_OUTPUT.PUT_LINE (i_prodid || ' was ' || q_prod(i_prodid)); UPDATE product SET descrip = i_descrip WHERE prodid = i_prodid; IF SQL%NOTFOUND THEN DBMS_OUTPUT.PUT_LINE ('Product ' || i_prodid || ' already exists!'); RAISE_APPLICATION_ERROR (-20202,'No products updated.'); ELSE DBMS_OUTPUT.PUT_LINE (i_prodid || ' updated to ' || q_prod(i_prodid)); END IF;END upd_prod;PROCEDURE del_prod (i_prodid IN product.prodid%TYPE)ISBEGIN DELETE FROM product WHERE prodid = i_prodid; IF SQL%NOTFOUND THEN DBMS_OUTPUT.PUT_LINE (i_prodid || ' does not exist!'); RAISE_APPLICATION_ERROR (-20203,'No products deleted.'); END IF;END DEL_PROD;FUNCTION q_prod (v_prodid IN product.prodid%TYPE) RETURN VARCHAR2IS v_descrip product.descrip%TYPE;BEGIN SELECT descrip INTO v_descrip FROM product WHERE prodid = v_prodid; RETURN (v_descrip);EXCEPTION WHEN NO_DATA_FOUND THEN RETURN 'Invalid Product Number';END q_prod;SQL> CREATE OR REPLACE PACKAGE prod_pack 2 IS 3 PROCEDURE add_prod 4 (i_prodid IN product.prodid%TYPE, 5 i_descrip IN product.descrip%TYPE); 6 PROCEDURE upd_prod 7 (i_prodid IN product.prodid%TYPE, 8 i_descrip IN product.descrip%TYPE); 9 PROCEDURE del_prod 10 (i_prodid IN product.prodid%TYPE); 11 END prod_pack; 12 /Package created.SQL> CREATE OR REPLACE PACKAGE BODY prod_pack 2 IS 3 -- 4 FUNCTION q_prod 5 (v_prodid IN product.prodid%TYPE) 6 RETURN VARCHAR2 7 IS 8 v_descrip product.descrip%TYPE; 9 BEGIN 10 SELECT descrip 11 INTO v_descrip 12 FROM product 13 WHERE prodid = v_prodid; 14 RETURN (v_descrip); 15 EXCEPTION 16 WHEN NO_DATA_FOUND THEN 17 RETURN 'Invalid Product Number'; 18 END q_prod; 19 -- 20 PROCEDURE add_prod 21 (i_prodid IN product.prodid%TYPE, 22 i_descrip IN product.descrip%TYPE) 23 IS 24 BEGIN 25 INSERT INTO product (prodid, descrip) 26 VALUES (i_prodid, i_descrip); 27 EXCEPTION 28 WHEN DUP_VAL_ON_INDEX THEN 29 DBMS_OUTPUT.PUT_LINE 30 ('Product ' || i_prodid || 31 ' already exists!'); 32 RAISE_APPLICATION_ERROR 33 (-20001,'Invalid Product ID'); 34 END add_prod; 35 -- 36 PROCEDURE upd_prod 37 (i_prodid IN product.prodid%TYPE, 38 i_descrip IN product.descrip%TYPE) 39 IS 40 BEGIN 41 DBMS_OUTPUT.PUT_LINE 42 (i_prodid || ' was ' || q_prod(i_prodid)); 43 UPDATE product 44 SET descrip = i_descrip 45 WHERE prodid = i_prodid; 46 IF SQL%NOTFOUND THEN 47 DBMS_OUTPUT.PUT_LINE 48 ('Product ' || i_prodid || 49 ' already exists!'); 50 RAISE_APPLICATION_ERROR 51 (-20202,'No products updated.'); 52 ELSE 53 DBMS_OUTPUT.PUT_LINE 54 (i_prodid || ' updated to ' || q_prod(i_prodid)); 55 END IF; 56 END upd_prod; 57 -- 58 PROCEDURE del_prod 59 (i_prodid IN product.prodid%TYPE) 60 IS 61 BEGIN 62 DELETE FROM product 63 WHERE prodid = i_prodid; 64 IF SQL%NOTFOUND THEN 65 DBMS_OUTPUT.PUT_LINE 66 (i_prodid || ' does not exist!'); 67 RAISE_APPLICATION_ERROR 68 (-20203,'No products deleted.'); 69 END IF; 70 END DEL_PROD; 71 -- 72 END prod_pack; 73 /Package body created.

Create a package called EMP_PACK. For now, the package contains one public function called get_dept_sal. The function, given a department number, will return the total salaries of the employees (EMP table) in that department. Test your packaged function with the following statement.SQL> VARIABLE DEPT_SAL NUMBER

SQL> EXECUTE :dept_sal := emp_pack.get_dept_sal(10)PL/SQL procedure successfully completed.SQL> PRINT dept_sal DEPT_SAL---------- 8750SQL> CREATE OR REPLACE PACKAGE emp_pack 2 IS 3 FUNCTION get_dept_sal 4 (i_deptno emp.deptno%TYPE) 5 RETURN NUMBER; 6 END emp_pack; 7 /Package created.SQL> CREATE OR REPLACE PACKAGE BODY emp_pack 2 IS 3 FUNCTION get_dept_sal 4 (i_deptno emp.deptno%TYPE) 5 RETURN NUMBER 6 IS 7 v_dept_sal emp.sal%TYPE; 8 BEGIN 9 SELECT SUM(sal) 10 INTO v_dept_sal 11 FROM emp 12 WHERE deptno = i_deptno; 13 RETURN v_dept_sal; 14 END get_dept_sal; 15 END emp_pack; 16 /Package body created.

9. 2. You need to add two functions to your EMP_PACK package. VALID_DEPTNO validates the department number. Given a department number, if that number exists in the DEPT table, it returns True, otherwise, it returns False.CHK_MGR ensures that, given a manager number and an employee number, both employees work for the same department and the manager is actually a manager The SQL code you need follows. The function returns True if valid and False if not.For example, Jones (7566) is a manager and is in the same department as Scott (7788) SQL> SELECT 'TRUE' AS "?" 2 FROM emp 3 WHERE empno = 7566 -- MANAGER 4 AND job = 'MANAGER'

5 AND deptno = (SELECT deptno 6 FROM emp 7 WHERE empno = 7788) -- EMPLOYEE 8 /?----TRUETest your package with the following block.SQL> BEGIN 2 IF emp_pack.VALID_DEPTNO(10) THEN 3 DBMS_OUTPUT.PUT_LINE('10 IS GOOD!'); 4 END IF; 5 IF emp_pack.VALID_DEPTNO(99) = FALSE THEN 6 DBMS_OUTPUT.PUT_LINE('99 IS NO GOOD!'); 7 END IF; 8 IF emp_pack.chk_mgr(7566,7788) THEN 9 DBMS_OUTPUT.PUT_LINE('7566,7788 IS GOOD!'); 10 END IF; 11 IF emp_pack.chk_mgr(7788,7566) = FALSE THEN 12 DBMS_OUTPUT.PUT_LINE('7788,7566 IS NO GOOD!'); 13 END IF; 14 END; 15 /10 IS GOOD!99 IS NO GOOD!7566,7788 IS GOOD!7788,7566 IS NO GOOD!PL/SQL procedure successfully completed.SQL> CREATE OR REPLACE PACKAGE emp_pack 2 IS 3 -- 4 FUNCTION get_dept_sal 5 (i_deptno emp.deptno%TYPE) 6 RETURN NUMBER; 7 -- 8 FUNCTION valid_deptno 9 (i_deptno emp.deptno%TYPE) 10 RETURN BOOLEAN; 11 -- 12 FUNCTION chk_mgr 13 (i_mgr emp.mgr%TYPE, 14 i_empno emp.empno%TYPE) 15 RETURN BOOLEAN; 16 -- 17 END emp_pack; 18 /Package created.CREATE OR REPLACE PACKAGE BODY emp_packIS-- FUNCTION get_dept_sal (i_deptno emp.deptno%TYPE) RETURN NUMBER IS v_dept_sal emp.sal%TYPE; BEGIN SELECT SUM(sal) INTO v_dept_sal FROM emp WHERE deptno = i_deptno; RETURN v_dept_sal; END get_dept_sal;-- FUNCTION valid_deptno (i_deptno emp.deptno%TYPE) RETURN BOOLEAN IS v_result VARCHAR2(1); BEGIN SELECT 'x' INTO v_result FROM dept WHERE deptno = i_deptno; -- IF YOU MADE IT THIS FAR, THE DEPTNO EXISTS! RETURN TRUE; EXCEPTION WHEN NO_DATA_FOUND THEN -- DEPTNO DOESN'T EXIST! RETURN FALSE; WHEN OTHERS THEN RETURN NULL; END valid_deptno;-- FUNCTION chk_mgr (i_mgr emp.mgr%TYPE, i_empno emp.empno%TYPE) RETURN BOOLEAN IS v_result VARCHAR2(1); BEGIN SELECT 'x' INTO v_result FROM emp WHERE empno = i_mgr AND job = 'MANAGER' AND deptno = (SELECT deptno FROM emp WHERE empno = i_empno); -- if you made it this far, the combo is good! RETURN TRUE; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN FALSE; WHEN OTHERS THEN RETURN NULL; END chk_mgr;END emp_pack;/

10. 3. It is now time to finalize your package. You need one more procedure added to your package that will insert new employees. The procedure NEW_EMP: a) a) Only requires an employee number and a name. The rest could be defaults. These defaults are Job

DEFAULT 'SALESMAN' Mgr

DEFAULT 7839

Sal

DEFAULT 1000

CommDEFAULT 0

DeptnoDEFAULT 30

Hiredate can be assumed to be midnight, today. (Hint: This can be built programmatically into your insert statement)b) b) Only allows the insert to take place if the department number is valid (VALID_DEPTNO).c) c) After the insert, determines whether the Manager and Employee number is a valid combination. If the combination is bad, rollback to a point before the insert. (Hint: SAVEPOINT)d) d) Currently, the order of your program units is important so ensure that NEW_EMP is the last unit defined in your package body. Test your newly improved package with the following statements.SQL> EXEC emp_pack.new_emp(1,'GRANT')PL/SQL procedure successfully completed.SQL> EXEC emp_pack.new_emp(2,'ROBERT',i_deptno => 99)BEGIN emp_pack.new_emp(2,'ROBERT',i_deptno => 99); END;*ERROR at line 1:ORA-20205: Invalid department number. Try again.ORA-06512: at "OLN.EMP_PACK", line 76ORA-06512: at line 1SQL> EXEC emp_pack.new_emp(3,'SPENCER',i_deptno => 10)BEGIN emp_pack.new_emp(3,'SPENCER',i_deptno => 10); END;*ERROR at line 1:ORA-20206: Invalid Manager for this employee!ORA-06512: at "OLN.EMP_PACK", line 83ORA-06512: at line 1SQL> SELECT empno, ename, job FROM emp where empno = 1;EMPNO ENAME JOB---------- ---------- --------- 1 GRANT SALESMANSQL> CREATE OR REPLACE PACKAGE emp_pack 2 IS 3 -- 4 FUNCTION get_dept_sal 5 (i_deptno emp.deptno%TYPE) 6 RETURN NUMBER; 7 -- 8 FUNCTION valid_deptno 9 (i_deptno emp.deptno%TYPE) 10 RETURN BOOLEAN; 11 -- 12 FUNCTION chk_mgr 13 (i_mgr emp.mgr%TYPE, 14 i_empno emp.empno%TYPE) 15 RETURN BOOLEAN; 16 -- 17 PROCEDURE new_emp 18 (i_empno emp.empno%TYPE, 19 i_ename emp.ename%TYPE, 20 i_job emp.job%TYPE DEFAULT 'SALESMAN', 21 i_mgr emp.mgr%TYPE DEFAULT 7698, 22 i_sal emp.sal%TYPE DEFAULT 1000, 23 i_comm emp.comm%TYPE DEFAULT 0, 24 i_deptno emp.deptno%TYPE DEFAULT 30); 25 26 END emp_pack; 27 /Package created.SQL> SQL> CREATE OR REPLACE PACKAGE BODY emp_pack 2 IS 3 -- 4 FUNCTION get_dept_sal 5 (i_deptno emp.deptno%TYPE) 6 RETURN NUMBER 7 IS 8 v_dept_sal emp.sal%TYPE; 9 BEGIN 10 SELECT SUM(sal) 11 INTO v_dept_sal 12 FROM emp 13 WHERE deptno = i_deptno; 14 RETURN v_dept_sal; 15 END get_dept_sal; 16 -- 17 FUNCTION valid_deptno 18 (i_deptno emp.deptno%TYPE) 19 RETURN BOOLEAN 20 IS 21 v_result VARCHAR2(1); 22 BEGIN 23 SELECT 'x' 24 INTO v_result 25 FROM dept 26 WHERE deptno = i_deptno; 27 -- IF YOU MADE IT THIS FAR, THE DEPTNO EXISTS! 28 RETURN TRUE; 29 EXCEPTION 30 WHEN NO_DATA_FOUND THEN -- DEPTNO DOESN'T EXIST! 31 RETURN FALSE; 32 WHEN OTHERS THEN 33 RETURN NULL; 34 END valid_deptno; 35 -- 36 FUNCTION chk_mgr 37 (i_mgr emp.mgr%TYPE, 38 i_empno emp.empno%TYPE) 39 RETURN BOOLEAN 40 IS 41 v_result VARCHAR2(1); 42 BEGIN 43 SELECT 'x' 44 INTO v_result 45 FROM emp 46 WHERE empno = i_mgr 47 AND job = 'MANAGER' 48 AND deptno = (SELECT deptno 49 FROM emp 50 WHERE empno = i_empno); 51 -- if you made it this far, the combo is good! 52 RETURN TRUE; 53 EXCEPTION 54 WHEN NO_DATA_FOUND THEN 55 RETURN FALSE; 56 WHEN OTHERS THEN 57 RETURN NULL; 58 END chk_mgr; 59 60 PROCEDURE new_emp 61 (i_empno emp.empno%TYPE, 62 i_ename emp.ename%TYPE, 63 i_job emp.job%TYPE DEFAULT 'SALESMAN', 64 i_mgr emp.mgr%TYPE DEFAULT 7698, 65 i_sal emp.sal%TYPE DEFAULT 1000, 66 i_comm emp.comm%TYPE DEFAULT 0, 67 i_deptno emp.deptno%TYPE DEFAULT 30) 68 IS 69 BEGIN 70 IF valid_deptno(i_deptno) THEN 71 SAVEPOINT before_insert; 72 INSERT INTO emp 73 VALUES (i_empno, i_ename, i_job, i_mgr, 74 TRUNC (SYSDATE), i_sal, i_comm, i_deptno); 75 ELSE 76 RAISE_APPLICATION_ERROR (-20205, 77 'Invalid department number. Try again.'); 78 END IF; 79 IF chk_mgr(I_mgr,I_empno) = TRUE THEN 80 NULL; 81 ELSE 82 ROLLBACK TO SAVEPOINT before_insert; 83 RAISE_APPLICATION_ERROR (-20206, 84 'Invalid Manager for this employee!'); 85 END IF; 86 END new_emp; 87 88 END emp_pack; 89 90 /Package body created.

This completes the practice.( Oracle Corporation, 2002Practice 9: More Package Concepts

In this practice, you modify the EMP_PACK package that you created in the previous practice; implementing the topics covered in this module. The solutions are described in SQL*Plus.Assumptions You have Procedure Builder installed on your workstation (if they want to do the practice in Procedure Builder). You have access to SQL*Plus (if you want to do the practice in SQL*Plus). You have access to a schema on an Oracle database. You have the privileges needed to create packages. You understand procedures and functions. You have EMP and DEPT tables. You have an EMP_PACK package from the last practice (although the code is available in this practice). Instructions11. 1. It is now time to enhance the EMP_PACK package that you created in the previous practice. (If you have lost it, the code is given at the end of this question). You decided that you would like the function get_dept_sal to return the total salary of the whole table if it is not passed a department number. Although you could use defaults for this, you decide you would like to overload the function.Test the package with the following statements.SQL> VAR SAL NUMBERSQL> EXEC :SAL := emp_pack.get_dept_sal(10)PL/SQL procedure successfully completed.SQL> PRINT SAL SAL

---------- 8750SQL> EXEC :SAL := emp_pack.get_dept_salPL/SQL procedure successfully completed.SQL> PRINT SAL SAL---------- 30025Here is the original specification and body of EMP_PACK.CREATE OR REPLACE PACKAGE emp_packIS-- FUNCTION get_dept_sal (i_deptno emp.deptno%TYPE) RETURN NUMBER;-- FUNCTION valid_deptno (i_deptno emp.deptno%TYPE) RETURN BOOLEAN;-- FUNCTION chk_mgr (i_mgr emp.mgr%TYPE, i_empno emp.empno%TYPE) RETURN BOOLEAN;-- PROCEDURE new_emp (i_empno emp.empno%TYPE, i_ename emp.ename%TYPE, i_job emp.job%TYPE DEFAULT 'SALESMAN', i_mgr emp.mgr%TYPE DEFAULT 7698, i_sal emp.sal%TYPE DEFAULT 1000, i_comm emp.comm%TYPE DEFAULT 0, i_deptno emp.deptno%TYPE DEFAULT 30);END emp_pack;/CREATE OR REPLACE PACKAGE BODY emp_packIS-- FUNCTION get_dept_sal (i_deptno emp.deptno%TYPE) RETURN NUMBER IS v_dept_sal emp.sal%TYPE; BEGIN SELECT SUM(sal) INTO v_dept_sal FROM emp WHERE deptno = i_deptno; RETURN v_dept_sal; END get_dept_sal;-- FUNCTION valid_deptno (i_deptno emp.deptno%TYPE) RETURN BOOLEAN IS v_result VARCHAR2(1); BEGIN SELECT 'x' INTO v_result FROM dept WHERE deptno = i_deptno; -- IF YOU MADE IT THIS FAR, THE DEPTNO EXISTS! RETURN TRUE; EXCEPTION WHEN NO_DATA_FOUND THEN -- DEPTNO DOESN'T EXIST! RETURN FALSE; WHEN OTHERS THEN RETURN NULL; END valid_deptno;-- FUNCTION chk_mgr (i_mgr emp.mgr%TYPE, i_empno emp.empno%TYPE) RETURN BOOLEAN IS v_result VARCHAR2(1); BEGIN SELECT 'x' INTO v_result FROM emp WHERE empno = i_mgr AND job = 'MANAGER' AND deptno = (SELECT deptno FROM emp WHERE empno = i_empno); -- if you made it this far, the combo is good! RETURN TRUE; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN FALSE; WHEN OTHERS THEN RETURN NULL; END chk_mgr; PROCEDURE new_emp (i_empno emp.empno%TYPE, i_ename emp.ename%TYPE, i_job emp.job%TYPE DEFAULT 'SALESMAN', i_mgr emp.mgr%TYPE DEFAULT 7698, i_sal emp.sal%TYPE DEFAULT 1000, i_comm emp.comm%TYPE DEFAULT 0, i_deptno emp.deptno%TYPE DEFAULT 30) IS BEGIN IF valid_deptno(i_deptno) THEN SAVEPOINT before_insert; INSERT INTO emp VALUES (i_empno, i_ename, i_job, i_mgr, TRUNC (SYSDATE), i_sal, i_comm, i_deptno); ELSE RAISE_APPLICATION_ERROR (-20205, 'Invalid department number. Try again.'); END IF; IF chk_mgr(I_mgr,I_empno) = TRUE THEN NULL; ELSE ROLLBACK TO SAVEPOINT before_insert; RAISE_APPLICATION_ERROR (-20206, Invalid Manager for this employee!); END IF; END new_emp;END emp_pack;/CREATE OR REPLACE PACKAGE emp_packIS-- FUNCTION get_dept_sal (i_deptno emp.deptno%TYPE) RETURN NUMBER;-- FUNCTION get_dept_sal RETURN NUMBER;--Rest of package is unchanged

CREATE OR REPLACE PACKAGE BODY emp_pack

IS

FUNCTION get_dept_sal

(i_deptno emp.deptno%TYPE)

RETURN NUMBER

IS

v_dept_sal emp.sal%TYPE;

BEGIN

SELECT SUM(sal)

INTO v_dept_sal

FROM emp

WHERE deptno = i_deptno;

RETURN v_dept_sal;

END get_dept_sal;

--

FUNCTION get_dept_sal

RETURN NUMBER

IS

v_dept_sal emp.sal%TYPE;

BEGIN

SELECT SUM(sal)

INTO v_dept_sal

FROM emp;

RETURN v_dept_sal;

END get_dept_sal;

Rest of package body is unchanged

12. 2. You decide that, as VALID_DEPTNO and CHK_MGR both return BOOLEAN and would not be used outside the package anyway, you want to make these members private. However, you are aware that, once private, the order in which your members appear within the body is very significant. You decide that you will use forward declarations so that you can place the private members anywhere within the package.Make VALID_DEPTNO and CHK_MGR private and add the forward declarations to your package body.Enter the following code to ensure everything is still working correctly.SQL> EXEC emp_pack.new_emp(2,'SPENCER')PL/SQL procedure successfully completed.SQL> EXEC emp_pack.new_emp(2,'SPENCER', i_deptno => 99)BEGIN emp_pack.new_emp(2,'SPENCER', i_deptno => 99); END;*ERROR at line 1:ORA-20205: Invalid department number. Try again.ORA-06512: at "OLN.EMP_PACK", line 97ORA-06512: at line 1SQL> EXEC emp_pack.new_emp(3,'ROBERT', i_deptno => 20)BEGIN emp_pack.new_emp(3,'ROBERT', i_deptno => 20); END;*ERROR at line 1:ORA-20206: Invalid Manager for this employee!ORA-06512: at "OLN.EMP_PACK", line 104ORA-06512: at line 1CREATE OR REPLACE PACKAGE emp_packIS-- FUNCTION get_dept_sal (i_deptno emp.deptno%TYPE) RETURN NUMBER;-- FUNCTION get_dept_sal RETURN NUMBER;-- PROCEDURE new_emp (i_empno emp.empno%TYPE, i_ename emp.ename%TYPE, i_job emp.job%TYPE DEFAULT 'SALESMAN', i_mgr emp.mgr%TYPE DEFAULT 7698, i_sal emp.sal%TYPE DEFAULT 1000, i_comm emp.comm%TYPE DEFAULT 0, i_deptno emp.deptno%TYPE DEFAULT 30);END emp_pack;/CREATE OR REPLACE PACKAGE BODY emp_packIS--FORWARD DECLARATIONS-------------- FUNCTION valid_deptno (i_deptno emp.deptno%TYPE) RETURN BOOLEAN;-- FUNCTION chk_mgr (i_mgr emp.mgr%TYPE, i_empno emp.empno%TYPE) RETURN BOOLEAN;--FORWARD DECLARATIONS END-----------Rest of package is unchanged

13. 3. You want to add a public function to your EMP_PACK package to implement the following business rule. A department number and job combination is valid if that combination currently exists in the EMP table. The function CHECK_DEPT_JOB receives a department number and job and, if that combination exists, returns TRUE, otherwise it returns FALSE. This processing promises to be rather heavy and, in most cases, repetitive, so you decide to add a one-time only procedure to your package to load a PL/SQL Index-by table and have this function access that instead. Test your function with the following block.SQL> BEGIN 2 IF emp_pack.check_dept_job('CLERK',20) THEN 3 DBMS_OUTPUT.PUT_LINE('VALID'); 4 END IF; 5 IF emp_pack.check_dept_job('CLERK',40) = FALSE THEN

6 DBMS_OUTPUT.PUT_LINE('INVALID'); 7 END IF; 8 END; 9 /VALIDINVALIDPL/SQL procedure successfully completed. (Hint: You will need to add four things to your package. An explicit cursor that would list out the department number and job combinations. A PL/SQL Index-by table that will store the ROWS returned by the cursor. A one-time only procedure that will load the PL/SQL Index-by table. The function CHECK_DEPT_JOB that will go through the PL/SQL Index-by table looking for matches.) (Hint 2: In the solutions, the cursor and the PL/SQL table are private. When you are trying this on your own, make them public and then, when everything works, make them private)Here is the final state of the package after all these questions.CREATE OR REPLACE PACKAGE emp_packIS-- FUNCTION get_dept_sal (i_deptno emp.deptno%TYPE) RETURN NUMBER;-- FUNCTION get_dept_sal RETURN NUMBER;-- PROCEDURE new_emp (i_empno emp.empno%TYPE, i_ename emp.ename%TYPE, i_job emp.job%TYPE DEFAULT 'SALESMAN', i_mgr emp.mgr%TYPE DEFAULT 7698, i_sal emp.sal%TYPE DEFAULT 1000, i_comm emp.comm%TYPE DEFAULT 0, i_deptno emp.deptno%TYPE DEFAULT 30); FUNCTION check_dept_job (i_job emp.job%TYPE, i_deptno emp.deptno%TYPE) RETURN BOOLEAN;END emp_pack;/CREATE OR REPLACE PACKAGE BODY emp_packIS -- CURSOR and INDEX-BY table used in One-Time only Proc CURSOR dept_job_c IS SELECT DISTINCT deptno, job FROM emp; TYPE dept_job_table_type IS TABLE OF dept_job_c%ROWTYPE INDEX BY BINARY_INTEGER; dept_job_table dept_job_table_type; counter PLS_INTEGER := 0;--FORWARD DECLARATIONS-------------- FUNCTION valid_deptno (i_deptno emp.deptno%TYPE) RETURN BOOLEAN;-- FUNCTION chk_mgr (i_mgr emp.mgr%TYPE, i_empno emp.empno%TYPE) RETURN BOOLEAN;--FORWARD DECLARATIONS END---------- FUNCTION get_dept_sal (i_deptno emp.deptno%TYPE) RETURN NUMBER IS v_dept_sal emp.sal%TYPE; BEGIN SELECT SUM(sal) INTO v_dept_sal FROM emp WHERE deptno = i_deptno; RETURN v_dept_sal; END get_dept_sal;-- FUNCTION get_dept_sal RETURN NUMBER IS v_dept_sal emp.sal%TYPE; BEGIN SELECT SUM(sal) INTO v_dept_sal FROM emp; RETURN v_dept_sal; END get_dept_sal;-- FUNCTION valid_deptno (i_deptno emp.deptno%TYPE) RETURN BOOLEAN IS v_result VARCHAR2(1); BEGIN SELECT 'x' INTO v_result FROM dept WHERE deptno = i_deptno; -- IF YOU MADE IT THIS FAR, THE DEPTNO EXISTS! RETURN TRUE; EXCEPTION WHEN NO_DATA_FOUND THEN -- DEPTNO DOESN'T EXIST! RETURN FALSE; WHEN OTHERS THEN RETURN NULL; END valid_deptno;-- FUNCTION chk_mgr (i_mgr emp.mgr%TYPE, i_empno emp.empno%TYPE) RETURN BOOLEAN IS v_result VARCHAR2(1); BEGIN SELECT 'x' INTO v_result FROM emp WHERE empno = i_mgr AND job = 'MANAGER' AND deptno = (SELECT deptno FROM emp WHERE empno = i_empno); -- if you made it this far, the combo is good! RETURN TRUE; EXCEPTION WHEN NO_DATA_FOUND THEN RETURN FALSE; WHEN OTHERS THEN RETURN NULL; END chk_mgr; PROCEDURE new_emp (i_empno emp.empno%TYPE, i_ename emp.ename%TYPE, i_job emp.job%TYPE DEFAULT 'SALESMAN', i_mgr emp.mgr%TYPE DEFAULT 7698, i_sal emp.sal%TYPE DEFAULT 1000, i_comm emp.comm%TYPE DEFAULT 0, i_deptno emp.deptno%TYPE DEFAULT 30) IS BEGIN IF valid_deptno(i_deptno) THEN SAVEPOINT before_insert; INSERT INTO emp VALUES (i_empno, i_ename, i_job, i_mgr, TRUNC (SYSDATE), i_sal, i_comm, i_deptno); ELSE RAISE_APPLICATION_ERROR (-20205, 'Invalid department number. Try again.'); END IF; IF chk_mgr(I_mgr,I_empno) = TRUE THEN NULL; ELSE ROLLBACK TO SAVEPOINT before_insert; RAISE_APPLICATION_ERROR (-20206, 'Invalid Manager for this employee!'); END IF; END new_emp; FUNCTION check_dept_job (i_job emp.job%TYPE, i_deptno emp.deptno%TYPE) RETURN BOOLEAN IS BEGIN FOR i IN dept_job_table.FIRST .. dept_job_table.LAST LOOP IF dept_job_table(i).deptno = i_deptno AND dept_job_table(i).job = i_job THEN RETURN TRUE; END IF; END LOOP; RETURN FALSE; -- MADE IT THIS FAR ... NEVER GOT A MATCH! END check_dept_job;--- Start of one time only procedure to load table.BEGIN FOR dept_job_c_rec IN dept_job_c LOOP counter := counter + 1; dept_job_table(counter) := dept_job_c_rec; END LOOP;END emp_pack;/

14. 4. Finally, you have decided that you would like to ensure the purity of the get_dept_sal function inside your emp_pack. You want to ensure that, at compile time, the compiler checks to ensure that this function does not access a database or a packaged variable. (Hint: PRAGMA )CREATE OR REPLACE PACKAGE emp_packIS-- FUNCTION get_dept_sal (i_deptno emp.deptno%TYPE) RETURN NUMBER; PRAGMA RESTRICT_REFERENCES(get_dept_sal,WNDS,WNPS,RNPS);-- FUNCTION get_dept_sal RETURN NUMBER; PRAGMA RESTRICT_REFERENCES(get_dept_sal,WNDS,WNPS,RNPS);--Rest of package specification unchanged

This completes the practice.( Oracle Corporation, 2002Practice 1: Oracle Supplied PackagesIn this practice you create user-defined procedure to drop a table, use the EXECUTE IMMEDIATE statement, and use the DBMS_JOB package. After completing these practices, you should be able to describe the use and application of some Oracle Server supplied packages like DBMS_OUTPUT, DBMS_JOB and DBMS_DDL.

InstructionsCreating a Procedure1) Create a procedure DROP_TABLE that drops the table specified in the input parameter. Use the procedures and functions from the supplied DBMS_SQL package.Test the DROP_TABLE procedure by creating a new table called EMP_DUP as a copy of the EMP table, then executing the DROP_TABLE procedure to drop the EMP_DUP table. SQL> CREATE OR REPLACE PROCEDURE drop_table 2 (v_table_name IN VARCHAR2) 3 IS 4 dyn_cur number; 5 dyn_err varchar2(255); 6 BEGIN 7 dyn_cur := DBMS_SQL.OPEN_CURSOR; 8 DBMS_SQL.PARSE(dyn_cur,'drop table '|| 9 v_table_name,DBMS_SQL.NATIVE);10 DBMS_SQL.CLOSE_CURSOR(dyn_cur);11 EXCEPTION12 WHEN OTHERS THEN dyn_err := sqlerrm;13 DBMS_SQL.CLOSE_CURSOR(dyn_cur);14 RAISE_APPLICATION_ERROR(-20600,dyn_err);15 END drop_table;16 /Procedure created.SQL> CREATE TABLE emp_dup2 AS SELECT * FROM emp;Table created.SQL> EXECUTE drop_table('emp_dup')PL/SQL procedure successfully completed.SQL> SELECT * FROM emp_dup; *ERROR at line 1:ORA-00942: table or view does not exist

Using the EXECUTE IMMEDIATE statement.2) Create another procedure DROP_TABLE2 that drops the table specified in the input parameter. Use the EXECUTE IMMEDIATE statement. Test the DROP_TABLE procedure by creating a new table called EMP_DUP as a copy of the EMP table, then executing the DROP_TABLE procedure to drop the EMP_DUP table.SQL> CREATE OR REPLACE PROCEDURE DROP_TABLE2 2 (v_table_name IN VARCHAR2)3 IS 4 BEGIN 5 EXECUTE IMMEDIATE 'DROP TABLE '||v_table_name; 6 END;7/Procedure created.SQL> CREATE TABLE emp_dup2 AS SELECT * FROM emp;Table created.SQL> EXECUTE drop_table2('emp_dup')PL/SQL procedure successfully completed.SQL> SELECT * FROM emp_dup; *ERROR at line 1:ORA-00942: table or view does not exist

Using the package DBMS_JOB Recreate the EMP_DUP table and schedule DROP_TABLE2 to run in five minutes time using DBMS_JOB. Note: a five minute interval is defined using the following code. SYSDATE + (5.0/24.0)/60.0(What is the increment of SYSDATE?) Confirm the job has been scheduled using USER_JOBS.SQL> CREATE TABLE emp_dup2 AS SELECT * FROM emp;Table created.SQL> VARIABLE JOBNO NUMBERSQL> EXECUTE DBMS_JOB.SUBMIT(:JOBNO, - 'DROP_TABLE2(''EMP_DUP'');', - SYSDATE + (5.0/24.0)/60.0)PL/SQL procedure successfully completed.SQL> PRINT JOBNO JOBNO-------------- 1SQL> SELECT JOB, NEXT_DATE, NEXT_SEC, WHAT 2 FROM USER_JOBS3 /JOB NEXT_DATE NEXT_SEC WHAT--- ---------- -------- --------------------- 1 30-SEP-2002 05:32:46 DROP_TABLE2(EMP_DUP);

Oracle Corporation, 2002 Practice 4: Database TriggersIn this practice you will learn how to create a trigger which involkes a stored procedure.InstructionsCreate a stored procedure which is invoked by a trigger.1) The business hours for our store are 8:00 a.m. to 10:00 p.m. Sunday through Friday, and 8:00 a.m. to 12:00 midnight on Saturday. To ensure that the ord table can only be modified during these hours, create a stored procedure that is called by a trigger for the ord table.a) Create a stored procedure called TIME_CHECK which checks the current time against the business hour times. If the current time is not within the business hours, use the RAISE_APPLICATION_ERROR procedure to give an appropriate error message.SQL> CREATE OR REPLACE PROCEDURE time_check2 IS3 BEGIN4 IF (TO_CHAR (SYSDATE, 'HH24:MI') NOT BETWEEN '08:00' 5 AND '22:00' AND TO_CHAR (SYSDATE, 'DY') IN ('SUN','MON',6 'TUE','WED', 'THU', 'FRI') ) 7 OR (TO_CHAR (SYSDATE,'HH24:MI') NOT BETWEEN '08:00' AND8 '24:00'AND TO_CHAR (SYSDATE, 'DY') = 'SAT' )9 THEN10 RAISE_APPLICATION_ERROR (-20205,'You may only make11 changes during normal12 office hours.');13 END IF;14 END time_check;15 /Procedure created.

b) Create a trigger called secure_ord on the ord table. Fire the trigger before data is inserted, updated, and deleted. Call your TIME_CHECK procedure from this trigger.SQL> CREATE OR REPLACE TRIGGER secure_ord 2 BEFORE INSERT OR UPDATE OR DELETE ON ord 3 BEGIN 4 time_check; 5 END secure_ord; 6 /Trigger created.

c) Test your trigger.SQL> insert into ord2 values (999, sysdate, 'A', 100,sysdate +7,1000);insert into ord values (999,sysdate,'A',100, sysdate + 7, 1000); *ERROR at line 1:ORA-20205: You may only make changes during normal office hours.ORA-06512: ORAxx.TIME_CHECK, line 18ORA-06512: ORAxx.SECURE_ORD, line 1ORA-04088: error during execution of trigger ORAxx. SECURE_ORD

Note: ORAxx is your username. Oracle Corporation, 2002Practice 7: Implementation of Database TriggersIn these practices, you will learn how to enforce data integrity within the server, protect data integrity with a trigger, enforce referential integrity within the server and compute derived data within the server.

InstructionsData integrity and referential integrity: 1. Create a trigger to ensure that once an order has been shipped, it can never be changed.a) Create a trigger ITEM_ORDER_SHIPPED. The trigger should be fired beforedata is inserted, updated or deleted in a row in the ITEM table. When a row is changed in the ITEM table, check to see if that row exists in the ORD table. If the SHIPDATE column has a value in the ORD table, fail the trigger. Add exception handling and give appropriate message if the trigger fails.SQL> CREATE OR REPLACE TRIGGER item_order_shipped 2 BEFORE INSERT OR UPDATE OR DELETE ON item 3 FOR EACH ROW 4 DECLARE 5 v_ordid number; 6 v_shipdate date; 7 BEGIN 8 SELECT ordid, shipdate 9 INTO v_ordid, v_shipdate10 FROM ord11 WHERE ordid = NVL(:NEW.ordid, :OLD.ordid);12 IF v_shipdate IS NOT NULL THEN13 RAISE_APPLICATION_ERROR(-20500,14'Corresponding order has already been shipped in15 the ORD table, no changes allowed.');16 END IF;17 EXCEPTION18 WHEN NO_DATA_FOUND THEN19RAISE_APPLICATION_ERROR(-20600,'Order does not exist');20 END;21 /Trigger created.

b) Create a trigger called ORD_ORDER_SHIPPED. Fire the trigger before every row that is changed due to updates and deletes in the ORD table. Use the WHEN clause to fire the trigger when the SHIPDATE column has a value. Raise an appropriate exception with an appropriate message informing the user that the order was already shipped.SQL> CREATE OR REPLACE TRIGGER ord_order_shipped 2 BEFORE UPDATE OR DELETE ON ord 3 FOR EACH ROW 4 WHEN (OLD.shipdate IS NOT NULL) 5 BEGIN 6 RAISE_APPLICATION_ERROR(-20550,' Corresponding 7 order has already been shipped,no changes 8 allowed.'); 9 END;10 /Trigger created.

Test the trigger. You can use the following data before and after creating the triggers.SQL> UPDATE item 2 SET qty = 20 3 WHERE ordid = 620 4 AND prodid = 100860;UPDATE item

*ERROR at line 1:ORA-20500: Corresponding order has already been shipped,no changes allowed.ORA-06512: at : ORAxx.ITEM_ORDER_SHIPPED, line 19ORA-04088: error during execution of trigger ORAxx.ITEM_ORDER_SHIPPED

Note: ORAxx is your username.SQL> UPDATE ord2 SET shipdate = sysdate3 WHERE ordid = 620;UPDATE ord

*ERROR at line 1:ORA-20550: Corresponding order has already been shipped,no changes allowed.ORA-06512: at : ORAxx.ORD_ORDER_SHIPPED, line 2ORA-04088: error during execution of trigger ORAxx.ORD_ORDER_SHIPPED

Drop these triggers before proceeding to the next exercise. SQL> DROP TRIGGER item_order_shipped;Trigger dropped.SQL> DROP TRIGGER item_order_shipped;Trigger dropped.

Compute derived data:2) Create a trigger that updates the TOTAL column in the ORD table after DML on the item table. a) The trigger is written on the ITEM table. After a row is added to the ITEM table, the amount from the ITEMTOT in the ITEM table is added to the amount in the TOTAL column of the ORD table. After a row is updated in the ITEM table, the adjusted amount in the ITEMTOT column in the ITEM table is added/subtracted to/from the amount in the TOTAL column of the ORD table. If a row is deleted from the ITEM table, the amount in the ITEMTOT column in the ITEM table is subtracted from the amount in the TOTAL column of the ORD table. Write a procedure to perform the necessary DML on the ORD table. Call the procedure with appropriate parameters from the trigger.SQL> CREATE OR REPLACE TRIGGER ord_total 2 BEFORE INSERT OR UPDATE OF itemtot OR DELETE ON item 3 FOR EACH ROW 4 BEGIN 5 IF INSERTING THEN 6 upd_ord(:NEW.ordid, :NEW.itemtot); 7 ELSIF UPDATING THEN 8 upd_ord(:NEW.ordid, :NEW.itemtot - :OLD.itemtot);9 ELSE - means DELETING10 upd_ord(:OLD.ordid, -:OLD.itemtot);11 END IF;12 END;13 /Trigger created.

SQL> CREATE OR REPLACE PROCEDURE upd_ord 2 (p_ordid IN NUMBER, p_itemtot IN NUMBER) 3 IS 4 BEGIN 5 UPDATE ord 6 SET total = NVL(total, 0) + NVL(p_itemtot, 0) 7 WHERE ordid = p_ordid; 8 END; 9 /Procedure created.

b) Test the trigger. You can use the following data before and after creating the triggers.SQL> SELECT * 2 FROM item 3 WHERE ordid = 621; ORDID ITEMID PRODID ACTUALPRICE QTY ITEMTOT------- ------- -------- ----------- ------ --------- 621 1 100861 45 10 450 621 2 100870 2.8 100 280

SQL> SELECT * 2 FROM ord 3 WHERE ordid = 621; ORDID ORDERDATE C CUSTID SHIPDATE TOTAL -------- ---------- - --------- ------------ ------- 621 15-MAR-1987 A 100 1-JAN-1987 730

SQL> INSERT INTO item2 VALUES(621, 3, 100871, 5.6, 100, 560);1 row created.

SQL> SELECT * 2 FROM item3 WHERE ordid = 621; ORDID ITEMID PRODID ACTUALPRICE QTY ITEMTOT------- ------- -------- ----------- ------ --------- 621 1 100861 45 10 450 621 2 100870 2.8 100 280 621 3 100871 5.6 100 560

SQL> SELECT * 2 FROM ord 3 WHERE ordid = 621; ORDID ORDERDATE C CUSTID SHIPDATE TOTAL -------- ---------- - --------- ------------ ------- 621 15-MAR-1987 A 100 1-JAN-1987 1290

Note: Drop the trigger before proceeding to the next exercise.

SQL> DROP TRIGGER ord_total;

Trigger dropped.

Oracle Corporation, 2002

Practice 9: Managing Stored Objects Using the Data Dictionary or Procedure BuilderIn this practice, you will learn how to manage stored objects using the data dictionary tables and views.

Instructions1. In a previous practice (Topic 4), you created a procedure which checks the current time against the business hour times. The business hours for our store have changed. The new business hours are 8:00 a.m. to 10:00 p.m. Sunday through Thursday, and 8:00 a.m. to 12:00 midnight on Friday and Saturday. To ensure that the ord table can only be modified during these hours, you created a trigger on the ord table. The trigger is fired before data is inserted, updated, and deleted. a) You cannot find the original script that created the trigger or the procedure. List the body of the secure_ord trigger in order to see the name of the procedure. Copy the body of the procedure and create a new script in order to enforce the new business hours.

SQL> SELECT trigger_body 2 FROM user_triggersWHERE trigger_name = 'SECURE_ORD';TRIGGER_BODY-----------------------------------------------------BEGIN time_check;END secure_ord;

SQL> SELECT text 2 FROM user_sourceWHERE name = 'TIME_CHECK'4 ORDER BY line;TEXT------------------------------------------------------------------PROCEDURE time_checkISBEGIN IF (TO_CHAR (SYSDATE, 'HH24:MI') NOT BETWEEN '08:00' AND '22:00''DY') IN ('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI')) OR (TO_CHAR (SYSDATE, 'HH24:MI') NOT BETWEEN '08:00' AND '24:00' AND TO_CHAR (SYSDATE, 'DY') = 'SAT' ) THEN RAISE_APPLICATION_ERROR (-20205, 'You may only make changes during normal office hours.'); END IF;END time_check;15 rows selected

SQL> CREATE OR REPLACE PROCEDURE time_check 2 ISBEGIN4 IF (TO_CHAR(SYSDATE,'HH24:MI') NOT BETWEEN '08:00' AND5 '22:00' 6 AND TO_CHAR(SYSDATE,'DY') IN ('SUN','MON','TUE', 7 'WED', 'THU'))8 OR (TO_CHAR(SYSDATE,'HH24:MI') NOT BETWEEN '08:00' AND9 '24:00' AND TO_CHAR(SYSDATE, 'DY') IN ('FRI', 'SAT'))10 THEN11 RAISE_APPLICATION_ERROR(-20205, 'You may only make12 changes during normal office hours.');13 END IF;14 END time_check;15 /Procedure created.

Note: when you work with Procedure Builder you need not to query the data dictionary for the text of the procedure and the body of the trigger. The trigger is stored by the table, the procedure youll find in the section Stored Program Units. You could simply copy the text of the procedure via the menu. After you have connected to the Procedure Builder with the username/password and connectstring provided to you, select Database Objects, select your username, then Stored Program Units. Activate the program TIME_CHECK. You now could copy the text of the procedure by using the menu; Program, choose Stored Program Unit Editor. Copy this, go to SQL*Plus, add the words Create or Replace before the text and save it as a file. In Procedure Builder you cant save text files.

b) Test your trigger.Note: In order for your trigger to fail, you may need to change the time to be outside the range of your current time while performing this exercise. SQL> insert into ord 2 values (999, sysdate, 'A', 100,sysdate + 7, 1000);insert into ord *error at line 1:ORA-20205: You may only make changes during normal office hours.ORA-06512: at ORAxx.TIME_CHECK, line 9ORA-06512: at ORAxx.SECURE_ORD, line 1ORA-04088: error during execution of trigger ORAxx.SECURE_ORD

Note: ORAxx is your username.

Oracle Corporation, 2002Practice 11: Managing DependenciesIn practice, you will compile your stored program units, track dependencies between stored program units and check their status.

Instructions1. In another practice (Practice 9), you recompiled a procedure to enforce business hour time for our store. The recompilation makes the dependent trigger INVALID. a) Recompile the procedure TIME_CHECK.

SQL> ALTER PROCEDURE time_check COMPILE;Procedure altered.

b) Find all dependent objects and their types on this procedure.

SQL> SELECT name, type2 FROM user_dependencies3 WHERE referenced_name = 'TIME_CHECK';NAME TYPE--------------------- --------------------SECURE_ORD TRIGGER

c) Check to see if these dependent objects are INVALID.

SQL> SELECT object_name, object_type, status 2 FROM user_objects;OBJECT_NAME OBJECT_TYPE STATUS--------------- ----------------- --------BONUS TABLE VALIDCUSTID SEQUENCE VALID. . .. . .. . .27 rows selected.

d) Create a procedure to dynamically recompile all dependent objects on this procedure. Use the procedure name as an input parameter. Make use of the ALTER_COMPILE procedure in the DBMS_DDL package. Execute the procedure you just created.SQL> CREATE OR REPLACE PROCEDURE compile_obj2 (p_obj_name IN VARCHAR2)3 IS4 CURSOR obj_cur IS5 SELECT name, type6 FROM user_dependencies7 WHERE referenced_name = UPPER(p_obj_name);8 BEGIN9 FOR obj_rec in obj_cur LOOP10 DBMS_DDL.ALTER_COMPILE(obj_rec.type, user, obj_rec.name);11 END LOOP;12 END;13 /Procedure created.SQL> EXECUTE compile_obj('TIME_CHECK')PL/SQL procedure successfully completed.

e) Check to see if these dependent objects are INVALID.SQL> SELECT object_name, object_type, status2 FROM user_objects;OBJECT_NAME OBJECT_TYPE STATUS--------------- ----------------- --------BONUS TABLE VALIDCOMPILE_OBJ PROCEDURE VALIDCUSTID SEQUENCE VALID. . .. . .. . .28 rows selected.

Oracle Corporation, 2002


Recommended