Overview Parameter Passing (review) Error Handling (review) Packages Specification Body Package Variables Execution Rights Collections (Aggregates) Dynamic SQL Nested Blocks Bulk Binds Returning Other Functions Parameter Passing Can be positional or named Consider the function my_proc(one Number, two Varchar2, three Number) Can call as My_proc(1,hi,2) My_proc(one=>1, three=>2,two=>hi) In positional only the last N arguments can take default values In named this restriction does not apply Parameter Default Values Consider the procedure my_proc(one Number, two Varchar2) You can specify default values -my_proc( one Number DEFAULT 5, two Varchar2 DEFAULT yes) Parameter Types IN Value must be provided for this parameter. The function can not change this value. OUT The item passed must be a variable in the scope of the calling procedure. This parameter can be assigned a value in the function but not used. When the function terminates the value in the variable is changed IN OUT Can be read/written within procedure, and will update the variable passed in the calling procedure when the function terminates. EXCEPTIONS EXCEPTION section at the end of a Procedure/Function for error handling A Throw-Catch paradigm without the Try block Thrown anywhere in program Caught in exception section Can handle system defined errors or user defined errors Each error must have a separate WHEN clause in the EXCEPTION section Defining Errors Several Predefined Execution Errors raised by the system Or Define your own in the declaration section my_error_type exception; Pre-Defined Errors ZERO_DIVIDE CASE_NOT_FOUND INVALID_CURSOR NO_DATA_FOUND TOO_MANY_ROWS VALUE_ERROR STORAGE_ERROR INVALID_NUMBER CURSOR_ALREADY_OPEN
TIMEOUT_ON_RESOURCE ROWTYPE_MISMATCH PROGRAM_ERROR LOGIN_DENIED NOT_LOGGED_ON DUP_VAL_ON_INDEX TRANSACTION_BACKED_ OUT Raising Errors Explicitly with RAISE(err_name) By the system executing your database commands Using Exceptions declare -- exceptions Exception_I_am_Lost exception; begin dbms_output.put_line('This is a test'); raise Exception_I_am_Lost; dbms_output.put_line('This should never print'); exception when ZERO_DIVIDE then dbms_output.put_line('You can not divide by zero'); when Exception_I_am_Lost then dbms_output.put_line('The program is Lost'); when OTHERS then dbms_output.put_line('An error I can not cope with'); end; Packages Groups of related functions, procedures and initialization code Borrowed from ADA as were named parameters Similar in concept to a class You have been using one DBMS_OUTPUT
Package Contents CREATE OR REPLACE my_package Package Specification Declare the Procedures, Functions, Variables, Types, Exceptions and Cursors for the package Package Body Define these items Package Variables Variables defined/initialized in package Specification are accessible within and without the package Body are private to the package. All functions/procedures share one copy Initialized when a user session first uses the package Not shared between users sessions Not retained after sessions terminated Can be used like class variables in C++/VB
CREATE PACKAGE BODY base_stat AS number_pers INT := 0;
Here the variable: number_pers is accessible to all functions in PACKAGE base_stat. But not outside Initialization Packages are initialized ONCE per session When you first use a package in a session Any Package Level variables are initialized They hold their values until your session terminates They are NOT shared with other users of the package. Access Rights Unless otherwise specified Stored PL-SQL (Procedures, Functions, Triggers and Packages) execute using the rights of the OWNER of the package not the executor The AUTHID clause can override this. AUTHID DEFINER AUTHID CURRENT_USER Using AUTHID CREATE [OR REPLACE] FUNCTION [schema_name.]function_name [(parameter_list)] RETURN datatype [AUTHID {CURRENT_USER | DEFINER}] {IS | AS} -- standalone procedure
-- package spec CREATE [OR REPLACE] PACKAGE [schema_name.]package_name [AUTHID {CURRENT_USER | DEFINER}] {IS | AS} Collections (Aggregates) Same as in any programming language Multi-Dimensional collections created by nesting types Requires you to define a type then instantiate it to use it Needed when you need to access several rows at once Arrays Have elements 1Size available for use at all times. All elements allocated at creation Tables Can have any number of elements Storage only allocated for indexes used Indexes need not be consecutive VARRAY declare type Score_List is vararry(50) of integer; Test_Scores Score_List;
Indexed by a binary integer Must be Initialized by a call to a constructor Test_Scores := Score_List(0,0,0,0,0,0,0,0,0,0) Referenced by subscript Test_Scores(4) := 98; Example of Varray create or replace procedure CollectionDemo1 (val integer) as type score_list is VARRAY(20) OF integer; vals score_list; begin vals:=score_list(0,1,2,3,4,5,6,7,8,9); dbms_output.put_line('hi there '||vals(val)); end; / TABLE OF declare Type Name_Table is table of VARCHAR2(20); SHIP_NAMES Name_Table:=Name_Table();
Indexed by binary integer Elements not allocated until an item is inserted Referenced by subscript Subscripts need not be sequential SHIP_NAMES.extend; SHIP_NAMES(4) := Kobayashi Maru Example of Table create or replace procedure CollectionDemo2 as type name_table is table of VARCHAR2(10); names name_table:=name_table(); sub integer; begin sub:=0; for row in (select lname from Staff order by lname) loop sub:=sub+1; names.extend; names(sub):=row.lname; end loop; dbms_output.put_line('Descending...........'); for sub in reverse 1..names.count loop dbms_output.put_line('hi there '||names(sub)); end loop; end; / Defining Collections Arrays TYPE type_name IS {VARRAY | VARYING ARRAY} ( size_limit) OF element_type [NOT NULL];
Tables TYPE type_name IS TABLE OF element_type [NOT NULL] INDEX BY [BINARY_INTEGER | PLS_INTEGER | VARCHAR2(size_limit)]; INDEX BY key_type; Dynamic SQL PL-SQL supports Queries/Cursors DML PL-SQL does not support SQL where the TABLES involved are not known beforehand DDL This is what the EXECUTE IMMEDIATE is used for Embedded SQL Syntax EXECUTE IMMEDIATE dynamic_string [INTO {define_variable[, define_variable]... | record}] [USING [IN | OUT | IN OUT] bind_argument [, [IN | OUT | IN OUT] bind_argument]...] [{RETURNING | RETURN} INTO bind_argument[, bind_argument]...]; Embedded SQL Examples Execute immediate create table SHUTTLE (NCC varchar2(20), ID Number);
Stmt := insert into VISIT values (NX2000, Iota, 07-NOV-2285,11-DEC-2285) Execute immediate Stmt; Execute immediate insert into PLANET values (:1,:2,:3) using RuraPenthe, 2, 3;
Using into to get values back declare Registry STARSHIP.REGISTRY%type; sql_query_stmt varchar2(120); v_class STARSHIP.CLASS%type; begin Registry :='NCC1701'; sql_query_stmt := 'select STARSHIP.CLASS from STARSHIP where STARSHIP.REGISTRY = '''||Registry||''''; execute immediate (sql_query_stmt)into v_class ; dbms_output.put_line(sql_query_stmt); dbms_output.put_line(v_class); end;
RefCursor RefCursor is a built in type You use it to build types for use in your code, not directly. It is really a pointer to a cursor It can be used to build dynamic sql that can handle multiple return values
type refcur_t is ref cursor; my_query varchar2(50) := 'Select TYPE.CLASS from TYPE'; my_class TYPE.CLASS%type; curr1 refcur_t; Using A Ref Cursor Open the Cursor While more rows Fetch in a row End While Close Cursor
open curr1 for my_query; loop fetch curr1 into my_class; exit when curr1%NOTFOUND; end loop; close curr1;
Nested Blocks You can define a block, procedure or function inside another. These may only be called from inside the function They define a new namespace Definitions of variables inside a block mask those from outside Nesting Example procedure Resize (n1 NUMBER, n2 NUMBER) is num1 NUMBER; num2 NUMBER; function Window (...) RETURN REAL IS num1 VARCHAR2; procedure Elapse (d1 DATE, d2 DATE) IS num2 DATE begin ... end; Proc Elapse begin ... end Func Window begin ... End Proc Resizes; Bulk Binds PL-SQL is interpreted and run by one module of the server process. SQL in the code is run by another Repetitive SQL causes context switches slowing down the code. Groups of SQL in PL-SQL can be bound together to be done at once using the forall keyword. bulk execute immediate statement can bulk bind SQL that affects multiple rows Bulk Bind Example declare type RegList is varray(3) of VARCHAR2; ships RegList := RegList(NCC1701,NCC1701D,NCC1701E); begin Forall j in 2..3 -- bulk-bind only part of varray update STARSHIP set STARSHIP.LOCATION = Sector 12 where STARSHIP.REGISTRY = ships(j); end; Returning A mechanism for getting info back into your program after DML Insert, Update and Delete can be modified by the Returning clause This returns column values from the affected row into your program. Works on one DML action at a time Returning Example Update PERSONEL set PERSONNEL.WAGES = PERSONNEL.WAGES * 1.1 where PERSONNEL.ID = MS388 returning PERSONNEL.NAME, PERSONNEL.WAGES into V_Name, V_Sal; Other Functions Pipes Allows named pipes to be used to pass information between sessions active on same server UTL_FILE Allows PL/SQL code to read/write from OS level files UTL_HTTP Allows PL/SQL code to connect via HTTP protocols