CPSC 4670 Database CPSC 4670 Database Security and AuditingSecurity and Auditing
Oracle PL/SQL: TriggersOracle PL/SQL: Triggers
11
TriggersTriggers
AnAn SQL trigger SQL trigger is a mechanism that is a mechanism that automatically executes a specified automatically executes a specified PL/SQL block when a triggering event PL/SQL block when a triggering event occurs on a table.occurs on a table.
The triggering event may be one ofThe triggering event may be one of insertinsert, , deletedelete, or , or updateupdate. .
The trigger is associated with a database The trigger is associated with a database table and table and is fired is fired when the triggering when the triggering event takes place on the table. event takes place on the table.
22
Triggers Triggers create [or replace] triggercreate [or replace] trigger trigger-name trigger-name{before | after}{before | after}{delete | insert | update [of column [, column] …]}{delete | insert | update [of column [, column] …]}[or[or{delete | insert | update [of column [, column …]}{delete | insert | update [of column [, column …]}]…]…ON table-nameON table-name[ [referencing {old [as] <old> [new [as] <new>][ [referencing {old [as] <old> [new [as] <new>]
| new [as] <new> [old [as] <old> }]| new [as] <new> [old [as] <old> }]for each rowfor each row[when (condition)] ][when (condition)] ]pl/sql_blockpl/sql_block
33
TriggersTriggers referencingreferencing specifies correlation names specifies correlation names
that can be used to refer to the old and that can be used to refer to the old and new values of the row components that new values of the row components that are being affected by the triggerare being affected by the trigger
for each rowfor each row designates the trigger to be designates the trigger to be a row trigger, i.e., the trigger is fired a row trigger, i.e., the trigger is fired once once for each rowfor each row that is affected by the that is affected by the triggering event and meets the optional triggering event and meets the optional trigger constraint defined in the when trigger constraint defined in the when clause. clause.
whenwhen specifies the trigger restriction. specifies the trigger restriction. 44
Trigger exampleTrigger example A trigger is executed when a row is A trigger is executed when a row is
inserted into the inserted into the odetails table. table. The trigger checks to see if The trigger checks to see if the quantity the quantity
orderedordered is more than is more than the quantity on the quantity on handhand. If it is, an error message is . If it is, an error message is generated, and the row is not inserted. generated, and the row is not inserted.
Otherwise, the trigger Otherwise, the trigger updatesupdates the the quantity on handquantity on hand for the part and checks for the part and checks to see if it has fallen below the reorder to see if it has fallen below the reorder level. If it has, it sends a row to the level. If it has, it sends a row to the restock table indicating that the part need table indicating that the part need to be reordered. to be reordered.
55
Trigger exampleTrigger example trig2.sqltrig2.sql trig2test.sqltrig2test.sql SQL> start trig2testSQL> start trig2testThen double check the restock Then double check the restock
table and part table for the table and part table for the results of trig2.sqlresults of trig2.sql
66
Trigger example (2)Trigger example (2) The trigger is defined on the The trigger is defined on the parts parts
tabletable and is triggered when the and is triggered when the price column column is updated. Each is updated. Each time someone updates the price time someone updates the price of a particular part, the trigger of a particular part, the trigger makes an entry in a log file of this makes an entry in a log file of this update along with the update along with the userid of of the person performing the update the person performing the update and the date of the update. and the date of the update.
77
Trigger example (2)Trigger example (2) The log file is created usingThe log file is created usingCreate table parts_log(Create table parts_log(
pnopno number(5),number(5),usernameusername char(8),char(8),update_dateupdate_date date,date,old_priceold_price number(6,2),number(6,2),new_pricenew_price number(6,2))number(6,2))
88
Trigger is defined asTrigger is defined as trig3.sqltrig3.sql SQL>update parts set price = SQL>update parts set price =
55.00 where pno = 1099;55.00 where pno = 1099; SQL> select * from parts_log;SQL> select * from parts_log; Use trig_tables.sql to test trig3.sqlUse trig_tables.sql to test trig3.sql
99
1010
Database Access Using Database Access Using CursorsCursors
Database Access Using Database Access Using CursorsCursors When the result of an SQL query When the result of an SQL query
((select statement) consists of statement) consists of more more than one rowthan one row, the simple , the simple select into statement can statement can notnot be used. be used.
A PL/SQL cursor allows the program A PL/SQL cursor allows the program to fetch and process information to fetch and process information from the database into the PL/SQL from the database into the PL/SQL program, one row at a time. program, one row at a time.
1111
Explicit CursorExplicit Cursor Explicit cursor: used for processing a Explicit cursor: used for processing a
query resulting in more than one row. query resulting in more than one row. Implicit cursor: is automatically defined Implicit cursor: is automatically defined
by PL/SQL for the select into statements, by PL/SQL for the select into statements, which result in one or fewer rows. which result in one or fewer rows.
1212
cursor <cname> [return-spec] is
<select-statement>;
Cursor ExampleCursor Example
cursor c1 cursor c1 return customers%rowtype return customers%rowtype isisselect * from customers;select * from customers;
cursor c2 iscursor c2 isselect pno, pname, price*markdown select pno, pname, price*markdown
sale_pricesale_pricefrom partsfrom parts
1313
has return clause
Use PL/SQL variable markdown
Process cursorProcess cursor One a cursor has been declared, it One a cursor has been declared, it
can be processed using the open, can be processed using the open, fetch, and close statements. fetch, and close statements.
open <cname>;open <cname>;fetch <cname> into <Record-or-fetch <cname> into <Record-or-
VariableList>;VariableList>;close <cname>;close <cname>;
1414
Explicit Cursor Explicit Cursor AttributesAttributesObtain status information about Obtain status information about a cursor.a cursor.
1515
Attribute Type Description
%ISOPEN Boolean Evaluates to TRUE if the cursor is open.
%NOTFOUND Boolean Evaluates to TRUE if the most recent fetch does not return a row.
%FOUND Boolean Evaluates to TRUE if the most recent fetch returns a row; complement of %NOTFOUND
%ROWCOUNT Number Evaluates to the total number of rows returned so far.
Creating a CursorCreating a Cursor We create a Cursor when we want to go over a We create a Cursor when we want to go over a
result of a query result of a query (like ResultSet in JDBC)(like ResultSet in JDBC) Syntax Example:Syntax Example:
DECLAREDECLARE cursor c iscursor c is select * from sailors; select * from sailors;
sailorData sailors%ROWTYPE;sailorData sailors%ROWTYPE; BEGINBEGIN open c;open c; fetch c intofetch c into sailorData; sailorData;
1616
sailorData is a variable that can hold a ROW from the sailors table
Here the first row of sailors is inserted into sailorData
Cursor ExampleCursor ExampleDECLARE Pi constant NUMBER(8,7) := 3.1415926; area NUMBER(14,2); cursor rad_cursor is select * from RAD_VALS; rad_val rad_cursor%ROWTYPE;
BEGIN open rad_cursor; fetch rad_cursor into rad_val; area:=pi*power(rad_val.radius,2); insert into AREAS values (rad_val.radius, area); close rad_cursor;END;/
radius
3
6
8
1717
Rad_cursor
fetch
Rad_val
Radius AreaAREAS
3 28.27
RAD_VALS
DECLARE … cursor rad_cursor is select * from RAD_VALS; rad_val rad_cursor%ROWTYPE;BEGIN open rad_cursor; fetch rad_cursor into rad_val; area:=pi*power(rad_val.radius,2); insert into AREAS values (rad_val.radius, area); …
1818
DECLARE … cursor rad_cursor is select * from RAD_VALS; rad_val RAD_VALS%ROWTYPE;BEGIN open rad_cursor; fetch rad_cursor into rad_val; area:=pi*power(rad_val.radius,2); insert into AREAS values (rad_val.radius, area); …
DECLARE … cursor rad_cursor is select radius from RAD_VALS; rad_val RAD_VALS.radius%TYPE;BEGIN open rad_cursor; fetch rad_cursor into rad_val; area:=pi*power(rad_val,2); insert into AREAS values (rad_val, area); …
DECLARE … cursor rad_cursor is select * from RAD_VALS; rad_val RAD_VALS.radius%TYPE;BEGIN open rad_cursor; fetch rad_cursor into rad_val; area:=pi*power(rad_val,2); insert into AREAS values (rad_val, area); …
Cursor ExampleCursor Example Use of the cursor statements and Use of the cursor statements and
attributesattributes p7.sqlp7.sql
1919
Cursor for loopCursor for loop This loop is very useful when all rows This loop is very useful when all rows
of the cursors are to be processed.of the cursors are to be processed.for <record_index> in <cname> loopfor <record_index> in <cname> loop
<loop-body>;<loop-body>;end loop;end loop; <record_index> is a record variable <record_index> is a record variable
that is implicitly declared by PL/SQL. that is implicitly declared by PL/SQL. Its scope is the for loop, and it can not Its scope is the for loop, and it can not be accessed outside the for loop. be accessed outside the for loop.
2020
Cursor for loopCursor for loop The loop terminates automatically The loop terminates automatically
when all rows of the cursor have when all rows of the cursor have been fetched. been fetched.
There is no need to open, fetch, There is no need to open, fetch, or close the curse, and there is no or close the curse, and there is no need to declare the record into need to declare the record into which the cursor rows are to be which the cursor rows are to be fetched. fetched.
2121
Cursor for loop Cursor for loop exampleexampledeclaredeclare
cursor c1 iscursor c1 isselect cno, cname, cityselect cno, cname, cityfromfrom customers, zipcodescustomers, zipcodeswherewhere customers.zip = zipcodes.zip;customers.zip = zipcodes.zip;
beginbeginforfor c1_rec c1_rec in in c1 c1 looploopdbms_output.put-line(‘Row number ’ || dbms_output.put-line(‘Row number ’ || c1%rowcount || c1%rowcount || ‘> ‘ || c_rec.cno || ‘ ‘ || c1-‘> ‘ || c_rec.cno || ‘ ‘ || c1-rec.cname || ‘ ‘ || c1_rec.city);rec.cname || ‘ ‘ || c1_rec.city);end loopend loop
end;end;2222
c1_rec
No declare for the record into which the cursor rows are to be fetched
Parameterized CursorsParameterized Cursors PL/SQL allows for cursors to take PL/SQL allows for cursors to take
input parameters. input parameters. cursor <cname> (<parameter-list>)cursor <cname> (<parameter-list>)
[return <return-spec>][return <return-spec>]is <select-statement>is <select-statement>
The parameters are specified The parameters are specified immediately after the cursor nameimmediately after the cursor name
2323
Parameterized CursorsParameterized CursorsCursor c3(Cursor c3(city_incity_in zipcodes.city%type) is zipcodes.city%type) is
select orders.eno, ename, sum(qty*price) Saleselect orders.eno, ename, sum(qty*price) Salefrom employees, orders, odetails, parts, zipcodesfrom employees, orders, odetails, parts, zipcodeswhere employees.eno = orders.eno and where employees.eno = orders.eno and
orders.ono = odetails.ono andorders.ono = odetails.ono andodetails.pno = parts.pno andodetails.pno = parts.pno andemployees.zip = zipcodes.zip employees.zip = zipcodes.zip
andandzipcodes.city = zipcodes.city = city_incity_in
Group by order.eno, enameGroup by order.eno, ename
2424
Given a city, this cursor returns the sales totals for every employee from that city
Parameterized CursorsParameterized Cursors The The openopen statement for such cursors statement for such cursors
will have the actual augment. will have the actual augment. open ci3(‘Wichita’);open ci3(‘Wichita’); If a cursor loop is used to process If a cursor loop is used to process
this cursorthis cursorfor c3_rec in c3(‘Wichita’) loopfor c3_rec in c3(‘Wichita’) loop……end loop;end loop;
2525
select for updateselect for update PL/SQL cursors can also be used to perform PL/SQL cursors can also be used to perform
updatesupdatescursor <cname> iscursor <cname> is
<select-statement> for update;<select-statement> for update; Select statement should involve only one Select statement should involve only one
database tabledatabase tableupdate <table-name>update <table-name>setset <set-clause><set-clause>where current of <cname>;where current of <cname>;
delete from < table-name >delete from < table-name >where current of <cname>;where current of <cname>;
2626
Example Example The price of every part whose The price of every part whose
quantity-on-hand value is more quantity-on-hand value is more than 175 is set to 80% of its old than 175 is set to 80% of its old price. price.
p8.sqlp8.sql
2727
Cursor variablesCursor variables Cursor variables are not required to have Cursor variables are not required to have
the SQL select statement associated the SQL select statement associated with them at the time of their with them at the time of their declaration. declaration.
Different SQL select statements can be Different SQL select statements can be associated with cursor variables at associated with cursor variables at different times. different times.
type <cursor-var-type-name> is ref cursortype <cursor-var-type-name> is ref cursor[return <return-type>];[return <return-type>];
2828
Cursor variables Cursor variables exampleexample Display the table whose name is an Display the table whose name is an
input parameterinput parameter A cursor variable is declared, with its A cursor variable is declared, with its
return type not state in the declaration. return type not state in the declaration. p9.sqlp9.sql SQL> execute SQL> execute
display_table(‘customers’)display_table(‘customers’) SQL> execute display_table(‘abcd’)SQL> execute display_table(‘abcd’)
2929
Records and TablesRecords and Tables
3030
RecordsRecords Table-based records, whose Table-based records, whose
structure is the same as that of a structure is the same as that of a row in a database table. row in a database table. p10.sql p10.sql
Cursor-based records is based on Cursor-based records is based on the select list of a cursor. the select list of a cursor. p11.sqlp11.sql
Programmer defined records. A type Programmer defined records. A type declaration is needed before record declaration is needed before record variables can be declared. variables can be declared. p12.sqlp12.sql
3131
Table-based recordsTable-based recordsDECLAREDECLARE customer_rec customers%rowtype;customer_rec customers%rowtype;BEGINBEGIN select * select * into into customer_reccustomer_rec from customers from customers where cno = '4444';where cno = '4444'; if (if (customer_reccustomer_rec.phone is null) then.phone is null) then dbms_output.put_line('Phone number is absent');dbms_output.put_line('Phone number is absent'); elseelse dbms_output.put_line('Phone number is ' || dbms_output.put_line('Phone number is ' ||
customer_reccustomer_rec.phone);.phone); end if;end if;END;END;//
3232
Cursor-based recordsCursor-based recordsDECLAREDECLARE cursor c1 iscursor c1 is select orders.eno select orders.eno
employee_no,employee_no, ename employee_name,ename employee_name, sum(price*qty) total_salessum(price*qty) total_sales from from
employees,orders,odetails,paremployees,orders,odetails,partsts
where employees.eno = where employees.eno = orders.eno orders.eno andand
orders.ono = odetails.ono orders.ono = odetails.ono andand
odetails.pno = parts.pnoodetails.pno = parts.pno group by orders.eno, ename;group by orders.eno, ename;
emp_sales_recemp_sales_rec c1%rowtype; c1%rowtype;
3333
BEGINBEGIN open c1;open c1; looploop fetch c1 into fetch c1 into emp_sales_recemp_sales_rec;; exit when c1%NOTFOUND;exit when c1%NOTFOUND; dbms_output.put_line(dbms_output.put_line(
emp_sales_recemp_sales_rec.employee_no .employee_no || ' || ' ' || ' ||
eemp_sales_recmp_sales_rec.employee_name || .employee_name || ' ' || ' ' || emp_sales_recemp_sales_rec.total_sales);.total_sales); end loop;end loop; close c1;close c1;END;END;//
Programmer defined Programmer defined recordsrecords
3434
DECLARE TYPE my_rec_type IS RECORD (number integer, name varchar2(20));
r1 my_rec_type; r2 my_rec_type;BEGIN r1.number := 111; r1.name := 'jones'; r2 := r1; dbms_output.put_line('Number = ' || r2.number ||
' Name = ' || r2.name);END;/
PL/SQL Tables PL/SQL Tables PL/SQL tables always consist of just PL/SQL tables always consist of just
one column indexed by binary integerone column indexed by binary integer They are sparse and provide direct They are sparse and provide direct
access to these rows, much like a access to these rows, much like a hash table. hash table.
type <table-type-name> is table of type <table-type-name> is table of <datatype><datatype>
Index by binary_integerIndex by binary_integer
3535
Operations of tablesOperations of tables countcount returns the number of elements in returns the number of elements in
the table. the table. n := the_table.count;n := the_table.count; deletedelete deletes the specified row or all deletes the specified row or all
rows. rows. the_table.delete(43);the_table.delete(43); exists exists returns true if there exists a row in returns true if there exists a row in
the specified index, otherwise, it returns the specified index, otherwise, it returns false.false. If the_table.exists(3) then … If the_table.exists(3) then …
first first returns the lowest-valued indexreturns the lowest-valued index last last returns the highest-valued indexreturns the highest-valued index next next returns the next-higher-valued indexreturns the next-higher-valued index prior prior returns the next-lower-valued indexreturns the next-lower-valued index
3636
Table exampleTable example Retrieves information from the Oracle Retrieves information from the Oracle
data dictionary table data dictionary table user_tab_columns user_tab_columns and prints the and prints the relational schemas of tables whose relational schemas of tables whose names start with the letter “Z”names start with the letter “Z”
p13.sqlp13.sql SQL> start p10SQL> start p10
3737
Built-In PackagesBuilt-In Packages dbms_output for debugging dbms_output for debugging
purposepurpose dbms_sql is used for executing dbms_sql is used for executing
dynamic SQ and PL/SQL dynamic SQ and PL/SQL statementsstatements
3838
dbms_output packagedbms_output package dbms_output package allows the dbms_output package allows the
user to display information to the user to display information to the session’s output device as the session’s output device as the PL/SQL program executes. PL/SQL program executes.
disabledisable all calls to the all calls to the dbms_output package. dbms_output package.
dbms_output.disabledbms_output.disableSQL> set serverouput offSQL> set serverouput off
3939
dbms_output packagedbms_output package enableenable enables all calls to the enables all calls to the
dbms_output package. dbms_output package. dbms_output.enable(1000000)dbms_output.enable(1000000) will will
initialize the buffer size to 1000000. initialize the buffer size to 1000000. Or Or dbms_output.enable;dbms_output.enable;SQL> set serveroutput on size SQL> set serveroutput on size
10000001000000SQL> set serveroutput onSQL> set serveroutput on
4040
dbms_output packagedbms_output package new_linenew_line inserts an en-of-line marker inserts an en-of-line marker
in the buffer.in the buffer. putput puts information into the buffer. puts information into the buffer. put-lineput-line is the same as put, except that is the same as put, except that
an end-of-line marker is also placed in an end-of-line marker is also placed in the buffer. the buffer.
get_lineget_line retrieves one line of retrieves one line of information from the buffer. information from the buffer.
get_linesget_lines retrieves a specified number retrieves a specified number of lines from the buffer. of lines from the buffer.
4141
dbms_sql Packagedbms_sql Package Execute nonquery statementsExecute nonquery statements
– Open the cursorOpen the cursor– Parse the statementParse the statement– Bind any input variablesBind any input variables– Execute the statementExecute the statement– Close the cursorClose the cursor
p18.sqlp18.sql4242
dbms_sql Packagedbms_sql Package Executing QueriesExecuting Queries
– Open the cursorOpen the cursor– Parse the statementParse the statement– Bind any input variablesBind any input variables– Define the output variablesDefine the output variables– Execute the queryExecute the query– Fetch the rowsFetch the rows– Return the results to PL/SQL variablesReturn the results to PL/SQL variables– Close the cursorClose the cursor
4343
dbms_sql Packagedbms_sql Package p20.qlp20.ql creates a package creates a package dsqldsql with two with two
procedures procedures get_columns get_columns and and get_query_resultsget_query_results..
p21.sqlp21.sql creates a package creates a package dsql_driver dsql_driver with with two procedures and uses the two procedures and uses the typestypes and and procedures procedures get_columns get_columns and and get_query_resultsget_query_results in p20.sql. in p20.sql.
p22.sqlp22.sql is an anonymous PL/SQL block that is an anonymous PL/SQL block that calls procedures calls procedures drive_get_query_resultsdrive_get_query_results from package from package dsql_driverdsql_driver in p21.sql in p21.sql
4444
Error HandlingError Handling PL/SQL implements run-time error PL/SQL implements run-time error
handling via exceptions and exception handling via exceptions and exception handlers. handlers.
when <exception-name> thenwhen <exception-name> then<Error-Handling-Code><Error-Handling-Code> User defined exceptionUser defined exception<exception-name> exception; <exception-name> exception; and are and are
raised using the syntaxraised using the syntaxraise <exception-name>raise <exception-name>
4545
Exception exampleException example
p40.sqlp40.sql SQL> execute insert_odetails(1234, 1111, -5);SQL> execute insert_odetails(1234, 1111, -5);
– 'Quantity is invalid''Quantity is invalid' SQL> execute insert_odetails(2000, 10900, 10);SQL> execute insert_odetails(2000, 10900, 10); SQL> execute insert_odetails(2000, 11001, 10);SQL> execute insert_odetails(2000, 11001, 10);
– 'PRIMARY KEY VIOLATION''PRIMARY KEY VIOLATION'
4646
ExercisesExercises Try all the following triggers:Try all the following triggers:
– trig1.sqltrig1.sql; ; trig2.sqltrig2.sql; ; trig2test.sqltrig2test.sql; ; trig3.sqltrig3.sql; ; trig_tables.sqltrig_tables.sql (SQL script for creating tables for the (SQL script for creating tables for the triggers).triggers).
Try all the following cursors:Try all the following cursors:– p7.sqlp7.sql; ; p8.sqlp8.sql (Updatable Cursor); (Updatable Cursor); p9.sqlp9.sql (Cursor (Cursor
Variable)Variable) Try all the following tables: Try all the following tables:
– p10.sqlp10.sql (Table-based record); (Table-based record); p11.sqlp11.sql (Cursor- (Cursor-based record); based record); p12.sqlp12.sql (Programmer-defined (Programmer-defined record) record)
Try the table: Try the table: p13.sqlp13.sql 4747
ExercisesExercises Try all the packagesTry all the packages
– p18.sqlp18.sql (DBMS_SQL Package -- (DBMS_SQL Package -- Executing non-query SQL) Executing non-query SQL)
– p19.sqlp19.sql (DBMS_SQL Package -- (DBMS_SQL Package -- Executing drop/create) Executing drop/create)
– p20.sqlp20.sql; ; p21.sqlp21.sql; ; p22.sqlp22.sql (DBMS_SQL - (DBMS_SQL - Executing Query) Executing Query)
Try the Exception Handling: p40.sqlTry the Exception Handling: p40.sql4848