--Example 8–23 Equivalent Invocations
WITH Different Notations IN Anonymous BLOCK
DECLARE
emp_num NUMBER
(6) := 120;
bonus NUMBER
(6) := 50;
PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER)
IS
BEGIN
UPDATE employees
SET salary = salary + amount
WHERE employee_id = emp_id;
END raise_salary;
BEGIN
-- Equivalent invocations:
raise_salary (emp_num, bonus); -- positional notation
raise_salary (amount => bonus, emp_id => emp_num);
-- named notation
raise_salary (emp_id => emp_num, amount => bonus);
-- named notation
raise_salary (emp_num, amount =>
bonus); -- mixed notation
END;
/
--Example 8–24 Equivalent Invocations
WITH Different Notations IN SELECT STATEMENTS
CREATE
OR REPLACE
FUNCTION compute_bonus (emp_id NUMBER, bonus NUMBER)
RETURN NUMBER
AUTHID DEFINER
IS
emp_sal NUMBER;
BEGIN
SELECT salary
INTO emp_sal
FROM employees
WHERE employee_id = emp_id;
RETURN emp_sal + bonus;
END compute_bonus;
/
SELECT
compute_bonus (120, 50) FROM DUAL;
-- positional
SELECT
compute_bonus (bonus =>
50, emp_id => 120) FROM DUAL;
-- named
SELECT
compute_bonus (120, bonus => 50) FROM DUAL;
-- mixed
--Example 8–25 Resolving PL/SQL PROCEDURE
Names
DECLARE
PROCEDURE swap (n1 NUMBER, n2 NUMBER)
IS
num1 NUMBER;
num2 NUMBER;
FUNCTION balance (bal NUMBER)
RETURN NUMBER
IS
x NUMBER
:= 10;
PROCEDURE swap (d1 DATE, d2 DATE)
IS
BEGIN
NULL;
END;
PROCEDURE swap (b1 BOOLEAN,
b2 BOOLEAN)
IS
BEGIN
NULL;
END;
BEGIN
-- balance
swap (num1, num2);
RETURN x;
END balance;
BEGIN -- enclosing procedure swap
NULL;
END swap;
BEGIN
-- anonymous block
NULL;
END;
-- anonymous block
/
--Example 8–26 Overloaded Subprogram
DECLARE
TYPE date_tab_typ IS TABLE OF DATE
INDEX BY PLS_INTEGER;
TYPE num_tab_typ IS TABLE OF NUMBER
INDEX BY PLS_INTEGER;
hiredate_tab date_tab_typ;
sal_tab num_tab_typ;
PROCEDURE initialize (tab OUT date_tab_typ, n INTEGER)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE
('Invoked first version');
FOR i IN 1 .. n
LOOP
tab (i) := SYSDATE;
END LOOP;
END initialize;
PROCEDURE initialize (tab OUT num_tab_typ, n INTEGER)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE
('Invoked second version');
FOR i IN 1 .. n
LOOP
tab (i) := 0.0;
END LOOP;
END initialize;
BEGIN
initialize (hiredate_tab, 50);
initialize (sal_tab, 100);
END;
/
--Example 8–27 Overload ERROR Causes
COMPILE-TIME ERROR
CREATE
OR REPLACE
PACKAGE pkg1
AUTHID DEFINER
IS
PROCEDURE s (p VARCHAR2);
PROCEDURE s (p VARCHAR2);
END pkg1;
/
--Example 8–28 Overload ERROR Compiles
Successfully
CREATE
OR REPLACE
PACKAGE pkg2
AUTHID DEFINER
IS
SUBTYPE t1 IS VARCHAR2
(10);
SUBTYPE t2 IS VARCHAR2
(10);
PROCEDURE s (p t1);
PROCEDURE s (p t2);
END pkg2;
/
--Example 8–29 Invoking Subprogram IN
Example 8–28 Causes COMPILE-TIME ERROR
CREATE
OR REPLACE
PROCEDURE p
AUTHID DEFINER
IS
a pkg2.t1 := 'a';
BEGIN
pkg2.s (a); -- Causes compile-time error PLS-00307
END p;
/
--Example 8–30 Correcting Overload ERROR
IN Example 8–28
CREATE
OR REPLACE
PACKAGE pkg2
AUTHID DEFINER
IS
SUBTYPE t1 IS VARCHAR2
(10);
SUBTYPE t2 IS VARCHAR2
(10);
PROCEDURE s (p1 t1);
PROCEDURE s (p2 t2);
END pkg2;
/
--Example 8–31 Invoking Subprogram IN
Example 8–30
CREATE
OR REPLACE
PROCEDURE p
AUTHID DEFINER
IS
a pkg2.t1 := 'a';
BEGIN
pkg2.s (p1 =>
a); -- Compiles without error
END p;
/
--Example 8–32 PACKAGE SPECIFICATION
WITHOUT Overload ERRORS
CREATE
OR REPLACE
PACKAGE pkg3
AUTHID DEFINER
IS
PROCEDURE s (p1 VARCHAR2);
PROCEDURE s (p1 VARCHAR2, p2 VARCHAR2
:= 'p2');
END pkg3;
/
--Example 8–33 Improper Invocation OF
Properly Overloaded Subprogram
CREATE
OR REPLACE
PROCEDURE p
AUTHID DEFINER
IS
a1 VARCHAR2
(10) := 'a1';
a2 VARCHAR2
(10) := 'a2';
BEGIN
pkg3.s (p1 =>
a1, p2 =>
a2); -- Compiles without error
pkg3.s (p1 =>
a1); -- Causes compile-time error PLS-00307
END p;
/
--Example 8–34 Implicit Conversion OF
PARAMETERS Causes Overload ERROR
CREATE
OR REPLACE
PACKAGE pack1
AUTHID DEFINER
AS
PROCEDURE proc1 (a NUMBER, b VARCHAR2);
PROCEDURE proc1 (a NUMBER, b NUMBER);
END;
/
CREATE
OR REPLACE
PACKAGE BODY pack1
AS
PROCEDURE proc1 (a NUMBER, b VARCHAR2)
IS
BEGIN
NULL;
END;
PROCEDURE proc1 (a NUMBER, b NUMBER)
IS
BEGIN
NULL;
END;
END;
/
BEGIN
pack1.proc1 (1, '2'); -- Compiles without error
pack1.proc1 (1, 2); -- Compiles without error
pack1.proc1 ('1', '2'); -- Causes compile-time error PLS-00307
pack1.proc1 ('1', 2); -- Causes compile-time error PLS-00307
END;
/
--Example 8–35 Recursive FUNCTION Returns
n Factorial (n!)
CREATE
OR REPLACE
FUNCTION factorial (n POSITIVE)
RETURN POSITIVE
AUTHID DEFINER
IS
BEGIN
IF n = 1
THEN -- terminating condition
RETURN n;
ELSE
RETURN n * factorial (n - 1); -- recursive invocation
END IF;
END;
/
BEGIN
FOR i IN 1 .. 5
LOOP
DBMS_OUTPUT.PUT_LINE
(i || '! = '
|| factorial (i));
END LOOP;
END;
/
--Example 8–36 Recursive FUNCTION Returns
nth Fibonacci NUMBER
CREATE
OR REPLACE
FUNCTION fibonacci (n PLS_INTEGER)
RETURN PLS_INTEGER
AUTHID DEFINER
IS
fib_1 PLS_INTEGER := 0;
fib_2 PLS_INTEGER := 1;
BEGIN
IF n = 1
THEN -- terminating condition
RETURN fib_1;
ELSIF n = 2
THEN
RETURN fib_2; -- terminating condition
ELSE
RETURN fibonacci (n - 2) + fibonacci (n - 1); -- recursive invocations
END IF;
END;
/
BEGIN
FOR i IN 1 .. 10
LOOP
DBMS_OUTPUT.PUT
(fibonacci (i));
IF i < 10
THEN
DBMS_OUTPUT.PUT
(', ');
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE
(' ...');
END;
/
--Example 8–37 Declaring AND Defining
RESULT-Cached FUNCTION
CREATE
OR REPLACE
PACKAGE department_pkg
AUTHID DEFINER
IS
TYPE dept_info_record IS RECORD
(
dept_name departments.department_name%TYPE,
mgr_name employees.last_name%TYPE,
dept_size PLS_INTEGER
);
-- Function declaration
FUNCTION get_dept_info (dept_id NUMBER)
RETURN dept_info_record
RESULT_CACHE;
END department_pkg;
/
CREATE
OR REPLACE
PACKAGE BODY department_pkg
IS
-- Function definition
FUNCTION get_dept_info (dept_id NUMBER)
RETURN dept_info_record
RESULT_CACHE
IS
rec dept_info_record;
BEGIN
SELECT department_name
INTO rec.dept_name
FROM departments
WHERE department_id = dept_id;
SELECT e.last_name
INTO rec.mgr_name
FROM departments d, employees e
WHERE d.department_id = dept_id AND d.manager_id = e.employee_id;
SELECT COUNT (*)
INTO rec.dept_size
FROM EMPLOYEES
WHERE department_id = dept_id;
RETURN rec;
END get_dept_info;
END department_pkg;
/
-- Global Configuration Settings
DROP TABLE global_config_params;
CREATE
TABLE global_config_params
(
name VARCHAR2 (20), -- parameter NAME
val VARCHAR2
(20), -- parameter VALUE
PRIMARY KEY (name)
);
-- Application-Level Configuration
Settings
CREATE
TABLE app_level_config_params
(
app_id VARCHAR2
(20), -- application ID
name VARCHAR2 (20), -- parameter NAME
val VARCHAR2
(20), -- parameter VALUE
PRIMARY KEY (app_id, name)
);
-- Role-Level Configuration Settings
CREATE
TABLE role_level_config_params
(
role_id VARCHAR2
(20), -- application (role) ID
name VARCHAR2 (20), -- parameter NAME
val VARCHAR2
(20), -- parameter VALUE
PRIMARY KEY (role_id, name)
);
--Example 8–38 RESULT-Cached FUNCTION
Returns Configuration Parameter Setting
CREATE
OR REPLACE
FUNCTION get_value (p_param VARCHAR2,
p_app_id NUMBER,
p_role_id NUMBER)
RETURN VARCHAR2
RESULT_CACHE
AUTHID DEFINER
IS
answer VARCHAR2
(20);
BEGIN
-- Is parameter set at role level?
BEGIN
SELECT val
INTO answer
FROM role_level_config_params
WHERE role_id = p_role_id AND name = p_param;
RETURN answer;
-- Found
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL; -- Fall through to following code
END;
-- Is parameter set at application level?
BEGIN
SELECT val
INTO answer
FROM app_level_config_params
WHERE app_id = p_app_id AND name = p_param;
RETURN answer;
-- Found
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL; -- Fall through to following code
END;
-- Is parameter set at global level?
SELECT val
INTO answer
FROM global_config_params
WHERE name = p_param;
RETURN answer;
END;
CREATE
OR REPLACE
FUNCTION fibonacci (n NUMBER)
RETURN NUMBER
RESULT_CACHE
AUTHID DEFINER
IS
BEGIN
IF (n = 0) OR (n = 1)
THEN
RETURN 1;
ELSE
RETURN fibonacci (n - 1) + fibonacci (n - 2);
END IF;
END;
/
--Example 8–39 RESULT-Cached FUNCTION
Handles SESSION-Specific SETTINGS
CREATE
OR REPLACE
FUNCTION get_hire_date (emp_id NUMBER)
RETURN VARCHAR
RESULT_CACHE
AUTHID DEFINER
IS
date_hired DATE;
BEGIN
SELECT hire_date
INTO date_hired
FROM HR.EMPLOYEES
WHERE EMPLOYEE_ID = emp_id;
RETURN TO_CHAR (date_hired);
END;
/
--If a common format is acceptable to all
sessions, specify a format mask, removing the dependency on NLS_DATE_FORMAT.
For example:
--TO_CHAR(date_hired, 'mm/dd/yy');
--Add a format mask parameter to
get_hire_date. For example:
CREATE
OR REPLACE
FUNCTION get_hire_date (emp_id NUMBER, fmt VARCHAR)
RETURN VARCHAR
RESULT_CACHE
AUTHID DEFINER
IS
date_hired DATE;
BEGIN
SELECT hire_date
INTO date_hired
FROM HR.EMPLOYEES
WHERE EMPLOYEE_ID = emp_id;
RETURN TO_CHAR (date_hired, fmt);
END;
/
--In Example 8–40, assume that a
table, config_tab, has a VPD policy that translates this query:
SELECT
VALUE
FROM config_tab
WHERE name = param_name;
--To this query:
SELECT
VALUE
FROM config_tab
WHERE name = param_name AND app_id = SYS_CONTEXT ('Config', 'App_ID');
--Example 8–40 Result-Cached Function
Handles Session-Specific Application Context
CREATE
OR REPLACE
FUNCTION get_param_value (
param_name VARCHAR,
appctx VARCHAR
DEFAULT SYS_CONTEXT ('Config', 'App_ID'))
RETURN VARCHAR
RESULT_CACHE
AUTHID DEFINER
IS
rec VARCHAR
(2000);
BEGIN
SELECT val
INTO rec
FROM config_tab
WHERE name = param_name;
RETURN rec;
END;
/
--Example 8–41 Caching One NAME AT A TIME
(Finer Granularity)
CREATE
OR REPLACE
FUNCTION get_product_name_1 (prod_id NUMBER,
lang_id VARCHAR2)
RETURN NVARCHAR2
RESULT_CACHE
AUTHID DEFINER
IS
result_ VARCHAR2
(50);
BEGIN
SELECT translated_name
INTO result_
FROM OE.Product_Descriptions
WHERE PRODUCT_ID = prod_id AND LANGUAGE_ID = lang_id;
RETURN result_;
END;
/
--Example 8–42 Caching Translated Names
One LANGUAGE AT A TIME (Coarser Granularity)
CREATE
OR REPLACE
FUNCTION get_product_name_2 (prod_id NUMBER,
lang_id VARCHAR2)
RETURN NVARCHAR2
AUTHID DEFINER
IS
TYPE product_names IS TABLE OF NVARCHAR2
(50)
INDEX BY PLS_INTEGER;
FUNCTION all_product_names (lang_id VARCHAR2)
RETURN product_names
RESULT_CACHE
IS
all_names product_names;
BEGIN
FOR c IN (SELECT
*
FROM OE.Product_Descriptions
WHERE LANGUAGE_ID = lang_id)
LOOP
all_names (c.PRODUCT_ID) := c.TRANSLATED_NAME;
END LOOP;
RETURN all_names;
END;
BEGIN
RETURN all_product_names (lang_id) (prod_id);
END;
/
--Example 8–43 PL/SQL Anonymous BLOCK
Invokes EXTERNAL PROCEDURE
-- Publish Adjuster.raiseSalary as
standalone PL/SQL procedure:
CREATE
OR REPLACE
PROCEDURE raise_salary (empid NUMBER, pct NUMBER)
AS
LANGUAGE JAVA
NAME 'Adjuster.raiseSalary (int,
float)'; -- call specification
/
BEGIN
raise_salary (120, 10);
-- invoke
Adjuster.raiseSalary by PL/SQL name
END;
/
--Example 8–44 PL/SQL STANDALONE
PROCEDURE Invokes EXTERNAL PROCEDURE
-- Java call specification:
CREATE
PROCEDURE java_sleep (milli_seconds IN NUMBER)
AS
LANGUAGE JAVA
NAME 'java.lang.Thread.sleep(long)';
/
CREATE
OR REPLACE
PROCEDURE sleep (milli_seconds IN NUMBER)
AUTHID DEFINER
IS
BEGIN
DBMS_OUTPUT.PUT_LINE
(DBMS_UTILITY.get_time ());
java_sleep (milli_seconds);
DBMS_OUTPUT.PUT_LINE
(DBMS_UTILITY.get_time ());
END;
/