Bài thực hành Bảo mật hệ thống thông tin số 5: PL/SQL có nội dung trình bày về xử lý ngoại lệ, bộ kiểm soát lỗi, procedure và function, cursor, trigger,... Mời các bạn cùng tham khảo chi tiết nội dung tài liệu.
Trang 1Bài th c hành s 5 ự ố
PL/SQL (2)
Tóm t t n i dung: ắ ộ
X lý ngo i lử ạ ệ
Procedure và Function
Cursor
Trigger
I X lý ngo i l ử ạ ệ
1. Gi i thi u v Exceptionớ ệ ề
Các Exception là các danh đ nh trong PL/SQL mà có th g p ph i trongị ể ặ ả khi th c thi m t kh i d n đ n thân chính c a các tác v s b k t thúc. M t kh iự ộ ố ẫ ế ủ ụ ẽ ị ế ộ ố luôn luôn k t thúc khi g p m t exception, nh ng có th ch ra m t exception handlerế ặ ộ ư ể ỉ ộ
đ thi hành tác v cu i cùng trể ụ ố ước khi kh i b k t thúc. N u exception đố ị ế ế ược ki mể soát (handled) thì exception s không truy n ra ngoài kh i hay ra môi trẽ ề ố ường. Hai nhóm chính c a exception là :ủ
Predefined: đã được đ nh nghĩa trị ước b i PL/SQL và dính v i cácớ ớ
mã l i xác đ nhỗ ị
Userdefined: khai báo trong kh i, ch thố ỉ ường dùng khi có nhu
c u c th v i chúng, ngoài ra có th g n chúng v i các mã l i c n thi t.ầ ụ ể ớ ể ắ ớ ỗ ầ ế
Trong bài này, chúng ta s t p trung vào các exception đã đ nh nghĩaẽ ậ ị
trước:
Trang 2INVALID_NUMBER 1722
CURSOR_ALREADY_OPEN 6511 TRANSACTION_BACKED_OUT 61
2. B ki m soát l iộ ể ỗ
N u m t exception x y ra, quy n đi u khi n s chuy n cho ph nế ộ ả ề ề ể ẽ ể ầ EXCEPTION trong kh i mà nó x y ra. N u exception đó không ki m soát đố ả ế ể ược trong
ph n này ho c là không có ph n này thì kh i s k t thúc v i exception unhandled vàầ ặ ầ ố ẽ ế ớ
có th tác đ ng đ n môi trể ộ ế ường ngoài
Ví d : ụ
BEGIN
INSERT INTO dept (deptno, dname)
VALUES (50, ’CLEANING’);
INSERT INTO dept (deptno, dname)
VALUES (50, ‘TRANING’);
Exception DUP_VAL_ON_INDEX xảy ra tại đây END;
Khối sẽ kết thúc với exception unhandled ORA-00001
Đ b y các s ki n này và ch n các exception, có th đ nh nghĩa cácể ẫ ự ệ ậ ể ị exception handler trong ph n EXCEPTION.ầ
Cú pháp:
Trang 3WHEN exceptionnidentifier THEN actions;
Trang 4Ví d : ụ
DECLARE
v_ename emp.ename%TYPE;
v_job emp.job%TYPE;
BEGIN
SELECT ename, job INTO v_name, v_job FROM emp
WHERE hiredate BETWEEN ‘01/01/92’ AND ‘31/12/92’;
EXCEPTION
WHEN no_data_found THEN
INSERT INTO error_tab VALUES (‘Nobody in 92’); WHEN too_many_rows THEN
INSERT INTO error_tab VALUES (‘More than one person in 92’);
END;
B ki m soát l i ‘WHEN OTHERS’: có th dùng đ nh nghĩa này độ ể ỗ ể ị ể
ch n t t c các exception còn l i ngoài các exception đã đ nh nghĩa trong ph nặ ấ ả ạ ị ầ EXCEPTION. Ph n này đầ ược đ t cu i cùng trong ph n EXCEPTION.ặ ố ầ
Ví d : ụ
BEGIN
SAVEPOINT so_far_so_good;
INSERT INTO statistics_tab VALUES (18, 25, 91);
EXCEPTION
WHEN dup_val_on_index THEN
ROLLBACK TO so_far_so_good;
WHEN OTHERS THEN
INSERT INTO error_tab VALUES (‘Error during block’);
END;
Trang 53. Các hàm dùng trong b y l iẫ ỗ
Khi m t exception x y ra, ta có th xác đ nh mã l i và câu chú c a nó.ộ ả ể ị ỗ ủ PL/SQL cung c p 2 hàm:ấ
SQLCODE Tr v mã l i c a exception đó N u dùng nó ngoài ph nả ề ỗ ủ ế ầ
EXCEPTION thì mã tr ra là 0ả
SQLERR
M
Tr v toàn b câu chú l i (error message) và có c mã l iả ề ộ ỗ ả ỗ
Ví d : ụ
DECLARE
error_message CHAR (100);
error_code NUMBER;
BEGIN
… EXCEPTION
WHEN OTHERS THEN
error_message := SUBSTR (SQLERRM, 1, 100);
error_code := SQLCODE;
INSERT INTO error VALUES (error_message, error_code);
END;
II Procedure
Cú pháp:
CREATE [OR REPLACE] PROCEDURE procedure_name [(parameter_name [IN | OUT | IN OUT] datatype )]
{IS | AS}
BEGIN
procedure_body END procedure_name;
Trang 6 Chú ý: Datatype là ki u c a tham s , đây ch khai báo ki u ch ko khai báo chi u dàiể ủ ố ở ỉ ể ứ ề
c a tham s Ví d không đủ ố ụ ược khai báo tham s là VARCHAR2(10) mà ph i khai báoố ả
là VARCHAR2
Trang 7Ví d : ụ
CREATE OR REPLACE PROCEDURE update_product_price(
p_product_id IN products.product_id%TYPE, p_factor IN NUMBER)
AS v_product_count INTEGER;
BEGIN SELECT COUNT(*) INTO v_product_count
FROM products WHERE product_id = p_product_id;
IF v_product_count = 1 THEN UPDATE products
SET price = price * p_factor WHERE product_id = p_product_id;
COMMIT;
END IF;
EXCEPTION WHEN OTHERS THEN ROLLBACK;
END update_product_price;
Vì procedure c n ph i g i trong kh i PL/SQL, nên n u mu n ch y nó t d u nh cầ ả ọ ố ế ố ạ ừ ấ ắ SQL*Plus ta dùng l nh EXECUTE ho c l ng nó trong c p BEGINEND.ệ ặ ồ ặ
Ví d : ụ
SQL> EXECUTE update_product_price(1, 1.5);
Hay có thể
SQL> BEGIN
2 update_product_price(1, 1.5);
3 END;
Trang 8III Function
Cú pháp:
CREATE [OR REPLACE] PROCEDURE procedure_name [(parameter_name [IN | OUT | IN OUT] datatype )]
RETURN datatype
{IS | AS}
BEGIN procedure_body END procedure_name;
Ví d : ụ
create or replace function get_dname( y number) return varchar2
is
m char(14);
begin select dname
into m from dept where deptno=y;
if SQL%notfound then
m:='Khong thay';
end if;
return (rtrim(m));
end;
Đ g i function ta g i tr c ti p ho c thông qua các phép gán.ể ọ ọ ự ế ặ
Ví d : ụ
SQL> select * from dept where dname=get_dname(10);
DEPTNO DNAME LOC - -
Trang 9-SQL> select get_dname (20) from dual;
GET_DNAME (20) -RESEARCH
IV Cursor
Oracle dùng các vùng làm vi c g i là ‘các vùng SQL dùng riêng’ (privateệ ọ SQL areas) đ thi hành các câu l nh SQL và l u tr thông tin c a quá trình. M tể ệ ư ữ ủ ộ cursor là m t c u trúc PL/SQL cho phép đ nh danh các vùng này và truy c p đ n cácộ ấ ị ậ ế thông tin l u trong nó. Có 2 ki u cursor :ư ể
Implicit Cursors
Được mô t b i PL/SQL là n dành cho t t c các câu l nhả ở ẩ ấ ả ệ DML và cho các query tr ra đ n hàng (ví d l nh SELECTả ơ ụ ệ dùng tr c ti p trong kh i).ự ế ố
Explicit Cursors
Mô t rõ ràng v i các danh đ nh trong kh i và đả ớ ị ố ược thao tác
b ng các câu l nh đ c tr ng trong các tác v c a kh i. Cácằ ệ ặ ư ụ ủ ố cursor hi n ch dành cho các query và cho phép nhi u hàngệ ỉ ề
được x lý t query.ử ừ
sau :
DECLARE
Đ nh tên c a cursor và c u trúc c a query th c thi trong nó. T iị ủ ấ ủ ự ạ
th i đi m này, query s đờ ể ẽ ược phân tích (các c t, b ng, …)ộ ả
nh ng ch a thi hànhư ư OPEN
Thi hành query ràng bu c các bi n có tham kh o đ n. Các hàngộ ế ả ế
tr v b i query g i là ‘active set’ và s n sàng cho vi c l y dả ề ở ọ ẵ ệ ấ ữ
li u.ệ FETCH L y d li u t hàng hi n t i vào các bi n. Hàng hi n t i là hàngấ ữ ệ ừ ệ ạ ế ệ ạ
mà cursor đang ch đ n. M i m t l n FETCH, cursor di chuy nỉ ế ỗ ộ ầ ể
Trang 10con tr đ n hàng k ti p trên active set, nh v y m i m t l nhỏ ế ế ế ư ậ ỗ ộ ệ FETCH s truy c p đ n các hàng khác nhau trong query.ẽ ậ ế
CLOSE
H y b t p các hàng đang làm vi c đủ ỏ ậ ệ ược sinh ra b i l nh OPENở ệ
cu i cùng c a cursor. Có th OPEN l i đố ủ ể ạ ược và nh v y s cóư ậ ẽ
t p hàng làm vi c m i h n.ậ ệ ớ ơ
Cú pháp:
CURSOR indentifier [(parameter details)] IS queryexpression;
Ví d : ụ
DECLARE CURSOR c1 IS
SELECT last_name, salary, hire_date, job_id FROM employees
WHERE employee_id = 120;
/* khai báo biến record để đại diện một hàng được fetch từ bảng employees */
employee_rec c1%ROWTYPE;
BEGIN mở cursor một cách tường minh sử dụng cursor này để fetch dữ liệu đổ vào employee_rec
OPEN c1;
FETCH c1 INTO employee_rec;
DBMS_OUTPUT.PUT_LINE('Employee name: '
|| employee_rec.last_name);
END;
Gi ng nh các implicit cursor, có 4 thu c tính đ bi t các thông tin vố ư ộ ể ế ề cursor. Khi dùng, thì ph i đ tên cursor trả ể ước các thu c tính này.ộ
Trang 11%FOUND Có giá tr TRUE n u l nh FETCH g n nh t t cursorl y đị ế ệ ầ ấ ừ ấ ược 1
hàng t active set, ngừ ượ ạ ẽc l i s là FALSE
%NOTFOUND Ngược v i %FOUNDớ
%ROWCOUNT Tr v s hàng đã FETCH đả ề ố ượ ừc t active set tính đ n hi n t iế ệ ạ
%ISOPEN TRUE n u cursor đang m , FALSE n u cursor đã đóng ho c ch aế ở ế ặ ư
được m trong kh iở ố
Ví d : ụ
IF c1%ISOPEN THEN
FETCH c1 INTO v_ename, v_sal, v_hiredate;
ELSE
OPEN c1;
END IF;
Ví d : ụ
LOOP
FETCH c1 INTO v_ename, v_sal, v_hiredate;
EXIT WHEN c1%ROWCOUNT > 10;
END LOOP;
Thường thì khi mu n x lý nhi u hàng t explicit cursor thì dùng m tố ử ề ừ ộ vòng l p v i l nh FETCH t i m i bặ ớ ệ ạ ỗ ướ ặc l p. N u quá trình ti p t c thì t t c cácế ế ụ ấ ả hàng trong active set s đẽ ược x lý. Khi m t l nh FETCH không thành công x y ra,ử ộ ệ ẩ thu c tính %NOTFOUND s là TRUE. M c dù v y, n u dùng l nh FETCH k ti pộ ẽ ặ ậ ế ệ ế ế thì s x y ra l i :ẽ ả ỗ
ORA-1002: Fetch out of sequence
L i này s k t thúc kh i thỗ ẽ ế ố ường là m t ộ unhandled exception. Vì th c nế ầ thi t ph i ki m tra s thành công c a m i l n FETCH trế ả ể ự ủ ỗ ầ ước khi ti p t c tham kh oế ụ ả cursor
Trang 12Ví d : ụ
OPEN cursor_1;
LOOP
FETCH cursor_1 INTO a, b, c, d;
EXIT WHEN cursor_1%NOTFOUND;
xử lý hàng hiện tại ở đây END LOOP;
Ví d : ụ
DECLARE CURSOR c1 IS
SELECT empno, sal, hiredate, rowid FROM emp WHERE depno=20 AND job=’ANALYST’ FOR UPDATE OF sal;
emp_record c1%ROWTYPE;
BEGIN
OPEN c1;
… FETCH c1 INTO emp_record;
…
IF emp_record.sal < 2000 THEN …
… END;
Ví d trên dùng FOR UPDATE trong query c a cursor. Nghĩa là các hàngụ ủ
tr v b i query s đả ề ở ẽ ược khóa không cho ai khác truy xu t vào khi OPEN đấ ược dùng. Khi b khóa t i cu i giao d ch, chúng ta không c n COMMIT.ỏ ạ ố ị ầ
Khi tham kh o ‘current row’ t m t explicit cursor, các l nh SQL có thả ừ ộ ệ ể dùng m nh đ WHERE CURRENT OF. Nó cho phép c p nh t hay xóa b t i hàngệ ề ậ ậ ỏ ạ
hi n t i.ệ ạ
Trang 13Ví d : ụ
FETCH c1 INTO emp_record;
IF emp_record.ename = ‘KING’ THEN
DELETE FROM emp WHERE CURRENT OF c1;
V Triggers
M t Database Trigger độ ượ ạc t o và l u tr trong PL/SQL block tư ữ ương ng v i table. Nóứ ớ
đượ ự ộc t đ ng g i đ n khi có s truy nh p đ n table tọ ế ự ậ ế ương ng v i các hành đ ng đ nhứ ớ ộ ị nghĩa
Cú pháp:
CREATE [OR REPLACE] TRIGGER trigger_name
BEFORE | AFTER
UPDATE | DELECT | INSERT (OF column) ON TABLE (FOR EACH ROW (WHEN condition))
BEGIN
PL/SQL block END trigger_name;
Ví d : ụ
T o b ng:ạ ả
CREATE TABLE product_price_audit (product_id INTEGER
CONSTRAINT price_audit_fk_products REFERENCES products(product_id), old_price NUMBER(5, 2),
new_price NUMBER(5, 2));
Trang 14 T o Triggerạ
CREATE OR REPLACE TRIGGER before_product_price_update
BEFORE UPDATE OF price
ON products
FOR EACH ROW WHEN (new.price < old.price * 0.75)
BEGIN
dbms_output.put_line('product_id = ' || :old.product_id); dbms_output.put_line('Old price = ' || :old.price);
dbms_output.put_line('New price = ' || :new.price);
dbms_output.put_line('The price reduction is more than 25%');
insert row into the product_price_audit table INSERT INTO product_price_audit ( product_id, old_price, new_price)
VALUES (:old.product_id, :old.price, :new.price);
END before_product_price_update;
Firing a Trigger: đ th y để ấ ược output t m t trigger, b n c n ph i ch y câu l nh:ừ ộ ạ ầ ả ạ ệ SET SERVEROUTPUT ON
UPDATE products
SET price = price * 7
WHERE product_id IN (5, 10);
product_id = 10
Old price = 15.99
New price = 11.19
The price reduction is more than 25%
product_id = 5
Old price = 49.99
New price = 34.99
The price reduction is more than 25%
2 rows updated.
Trang 15 Disable and Enable Trigger
Có th c m m t trigger ho t đ ng và ngể ấ ộ ạ ộ ượ ạ ằc l i b ng câu l nh ALTER TRIGGER.ệ ALTER TRIGGER before_product_price_update DISABLE;
ALTER TRIGGER before_product_price_update ENABLE;
VI Bài t p ậ
Các bài t p trong bài lab này có s d ng đ n b ng Message đã đậ ử ụ ế ả ược mô t trong bài labả 4
1 Đo n mã sau đây c n ph i đạ ầ ả ược thi hành trong m t vòng l p v i các giá tr khác nhauộ ặ ớ ị
c a v t i m i bủ ạ ỗ ướ ặc l p (t m t 1 đ n 10).ầ ừ ế
UPDATE message SET numcol2 = 100 WHERE numcol1 = v;
N u b t k quá trình UPDATE nào mà không có ho c có nhi u h n 1 hàng thìế ấ ỳ ặ ề ơ thoát kh i vòng l p (Có th dùng SQL%ROWCOUNT đ ki m tra).ỏ ặ ể ể ể
2 S a đ i kh i b n đã vi t trong bài t p bài 2 Đ nh nghĩa l i bi n PL/SQL làử ổ ố ạ ế ậ ị ạ ế NUMBER(1). Đi u gì s x y ra n u giá tr gán vào là 42.Thêm m t b ki m soátề ẽ ả ế ị ộ ộ ể exception vào kh i đ l u l i các câu chú gi i thích trong MESSAGE cho b t k ki uố ể ư ạ ả ấ ỳ ề exception x y ra nào. Ch y kh i m t l n n a.ả ạ ố ộ ầ ữ
3 Dùng explixit cursor và các thu c tính c a nó:ộ ủ
Cho b ng Dept g m các thu c tính ID phòng ban, tên phòng ban và đ a đi m c aả ồ ộ ị ể ủ phòng ban các chi nhánh khác nhau.ở
Dept( ID, dname, loc)
X lý m i hàng c a b ng ‘Dept’, di chuy n phòng SALES đ n đ a đi m Dallas và cácử ỗ ủ ả ể ế ị ể phòng khác đ n New York. Ngoài ra nó đ m s phòng ban t i m i đ a đi m.ế ế ố ạ ỗ ị ể
4 T o ra m t file cript SQL*Plus ch p nh n m t tham s đ n là ki u ngh nghi p lúcạ ộ ấ ậ ộ ố ơ ể ề ệ
ch y chạ ương trình :
Ví d : ụ @UNIT3_FILE MANAGER
Trang 16Trong kh i PL/SQL, s dùng l nh SELECT l y các hàng t b ng ‘ố ẽ ệ ấ ừ ả emp’ v i đi uớ ề
ki n ‘ệ job’ là tham s nh p vào (Tham kh o đ n tham s b ng ‘ố ậ ả ế ố ằ &1’). G i m t chú gi iử ộ ả
đ n b ng MESSAGE tùy vào vi c có hàng, không hàng ho c m t vài hàng đế ả ệ ặ ộ ược tr v ả ề
Ví d : ụ ‘Jobtype found once’
‘Jobtype found more than once’
‘Jobtype not found’
L u ư jobtype trong b ng MESSAGE và COMMIT giao d ch đ chú gi i đả ị ể ả ượ c
t o ra.ạ