how to manually cache the values of function calls in 10g - oracle

I have the following code
CREATE OR REPLACE FUNCTION slow_function (p_in IN NUMBER)
RETURN NUMBER
AS
BEGIN
DBMS_LOCK.sleep(1);
RETURN p_in;
END;
/
CREATE OR REPLACE PACKAGE cached_lookup_api AS
FUNCTION get_cached_value (p_id IN NUMBER)
RETURN NUMBER;
PROCEDURE clear_cache;
END cached_lookup_api;
/
CREATE OR REPLACE PACKAGE BODY cached_lookup_api AS
TYPE t_tab IS TABLE OF NUMBER
INDEX BY BINARY_INTEGER;
g_tab t_tab;
g_last_use DATE := SYSDATE;
g_max_cache_age NUMBER := 10/(24*60); -- 10 minutes
-- -----------------------------------------------------------------
FUNCTION get_cached_value (p_id IN NUMBER)
RETURN NUMBER AS
l_value NUMBER;
BEGIN
IF (SYSDATE - g_last_use) > g_max_cache_age THEN
-- Older than 10 minutes. Delete cache.
g_last_use := SYSDATE;
clear_cache;
END IF;
BEGIN
l_value := g_tab(p_id);
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Call function and cache data.
l_value := slow_function(p_id);
g_tab(p_id) := l_value;
END;
RETURN l_value;
END get_cached_value;
-- -----------------------------------------------------------------
-- -----------------------------------------------------------------
PROCEDURE clear_cache AS
BEGIN
g_tab.delete;
END;
-- -----------------------------------------------------------------
END cached_lookup_api;
/
I want to pass two parameters "pi_value1" and "pi_value2" both of varchar2 to the function slow_function instead of "p_in". Is is possible to cache the results with two in parameters in oracle 10g .
the above code works fine with 1 parameter.
Please any one explain?

You'd need to create a two-dimensional array type to cache the values. Something along the lines of this (omitting the cache expiration code since that isn't changing)
CREATE OR REPLACE PACKAGE BODY cached_lookup_api
AS
TYPE t_pi_value2_tbl IS TABLE OF NUMBER
INDEX BY VARCHAR2(100);
TYPE t_cache IS TABLE OF t_pi_value2_tbl
INDEX BY VARCHAR2(100);
g_cache t_cache;
FUNCTION get_cached_value( p_pi_value1 IN VARCHAR2,
p_pi_value2 IN VARCHAR2 )
IS
BEGIN
RETURN g_cache(p_pi_value1)(p_pi_value2);
EXCEPTION
WHEN no_data_found
THEN
g_cache(p_pi_value1)(p_pi_value2) := slow_function( p_pi_value1, p_pi_value2 );
RETURN g_cache(p_pi_value1)(p_pi_value2);
END;
END;

Related

PL/SQL "all_search" procedure is not a procedure or is undefined

This function is inside a package, but when I call the function the following error appears: PL/SQL "all_search" is not a procedure or is undefined. Someone can help me?
CREATE OR REPLACE PACKAGE employee_tab IS
FUNCTION all_search (ID_EMP in NUMBER) RETURN O_T_EMPL PIPELINED;
END employee_tab;
/
CREATE OR REPLACE TYPE O_T_EMPL AS TABLE OF O_EMPLOYEE;
/
CREATE OR REPLACE PACKAGE BODY employee_tab IS
FUNCTION all_search (ID_EMP in NUMBER) RETURN O_T_EMPL PIPELINED
IS
TAB_OBJC_EMP O_T_EMPL;
MY_QUERY_SEARCH VARCHAR2(400);
REF_C SYS_REFCURSOR;
MAX_ROW NUMBER := 25;
BEGIN
MY_QUERY_SEARCH := 'SELECT *
FROM EMPLOYEES
WHERE EMPLOYEE_ID = ID_EMP';
open REF_C for MY_QUERY_SEARCH using ID_EMP;
loop
--
fetch REF_C bulk collect into TAB_OBJC_EMP limit MAX_ROW;
exit when TAB_OBJC_EMP.count = 0;
for i in 1..TAB_OBJC_SEE.count
--
loop
pipe row(O_EMPLOYEE(TAB_OBJC_EMP(i).V_O_EMP_ID,
TAB_OBJC_EMP(i).V_O_HIRE_ID,
TAB_OBJC_EMP(i).V_O_DEP_ID)
);
end loop;
--
END loop;
--
CLOSE REF_C;
RETURN;
--
END all_search;
END employee_tab;
/
call function: employee_tab.all_search(1);
You need to assign the result of the function to something, try something like:
DECLARE
l_emp_id NUMBER;
BEGIN
SELECT EMP_ID
INTO l_emp_id
FROM TABLE(employee_tab.all_search(1))
WHERE rownum = 1;
DBMS_OUTPUT.put_line(TO_CHAR(EMP_ID));
END;
/

Oracle - Get function parameter value in cursor

I have a package where I have created one function like this
create or replace package pk_server_control
is
function fn_get_employees_by_consultant(consultant_id number) return number;
end;
-----------------------------------------------------------------
create or replace package body pk_server_control
is
**function fn_get_employees_by_consultant(consultant_id number)
return number
is
cursor employees is select c.CST_NAME, a.NO_OF_EMPLOYEES from NISHAN_LDS_ACCOUNT a join NISHAN_LDS_CONSULTANT c
on c.CONSULTANT_ID = a.FK1_CONSULTANT_ID where c.CONSULTANT_ID =consultant_id ;
total number := 0; **
begin
for data in employees
loop
total := total + data.NO_OF_EMPLOYEES;
end loop;
return total;
end;
end;
begin
dbms_output.put_line(pk_server_control.fn_get_employees_by_consultant(1));
end;
I need to get value from the parameter "consultant_id number" of function "fn_get_employees_by_consultant" into "consultant_id" of the cursor "". While running, it doesn't give an error also it doesn't pass the value. Please help me to get through this :)
Try this
create or replace package pk_server_control
is
function fn_get_employees_by_consultant(consultant_id number) return number;
end;
-----------------------------------------------------------------
create or replace package body pk_server_control
is
function fn_get_employees_by_consultant(consultant_id number)
return number
is
val number := consultant_id;
cursor employees is select c.CST_NAME, a.NO_OF_EMPLOYEES from NISHAN_LDS_ACCOUNT a join NISHAN_LDS_CONSULTANT c
on c.CONSULTANT_ID = a.FK1_CONSULTANT_ID where c.CONSULTANT_ID =val;
total number := 0;
begin
for data in employees
loop
total := total + data.NO_OF_EMPLOYEES;
end loop;
return total;
end;
end;
begin
dbms_output.put_line(pk_server_control.fn_get_employees_by_consultant(3));
end;

Procedure checking set up parameters (PL/SQL, ORACLE)

In the package I have couple of procedure that set global variables, example below:
...
PROCEDURE setA (pp IN VARCHAR2)
IS BEGIN global_vName := pp; END;
PROCEDURE setB (qq IN VARCHAR2)
IS BEGIN global_vColor := qq; END;
FUNCTION getA RETURN VARCHAR2
IS BEGIN RETURN global_vName; END;
FUNCTION getB RETURN VARCHAR2
IS BEGIN RETURN global_vColor; END;
...
Now in the PL/SQL block I'm doing test if they are working correclty:
Begin
mypack.setA('NameA');
mypack.setB('ColorB');
End;
How to write a procedure that will check if global_vName and global_vColor are set up?
If they are null procedure should return exception. Please help.
Do you mean this?
FUNCTION getA RETURN VARCHAR2 IS
BEGIN
IF global_vName IS NULL THEN
RAISE NO_DATA_FOUND;
END IF;
RETURN global_vName;
END;
There is no possibility to execute some code after the end statement - you should write it explicitly if you need additional check. As I understand, you want be sure that global variables are always initialized, so you can use the package initialization:
create or replace package body mypack as
PROCEDURE setA (pp IN VARCHAR2)
IS BEGIN global_vName := pp; END;
PROCEDURE setB (qq IN VARCHAR2)
IS BEGIN global_vColor := qq; END;
FUNCTION getA RETURN VARCHAR2
IS BEGIN RETURN global_vName; END;
FUNCTION getB RETURN VARCHAR2
IS BEGIN RETURN global_vColor; END;
< here are your other functions and procedures >
begin
-- here is an initialization section
setA('NameA');
setB('ColorB');
end mypack;
The initialization section will be executed automatically by Oracle before the first user's call to package (function, procedure, cursor, variable, etc.). So you can be sure that your variables are always initialized.

Call Oracle function with a cursor IN/OUT

I am trying to make a simple call to a function(Test2) which takes a cursor, and returns a cursor.
I am stuck with the error:
Error(23,17): PLS-00306: wrong number or types of arguments in call to 'TEST2'
What is wrong with my function call?
v_resp := TEST2(v_req);
Here is my test:
CREATE OR REPLACE TYPE TRANS_OBJ AS OBJECT (TRANSNO CHAR(8));
CREATE OR REPLACE TYPE TRANS_OBJ_TAB AS TABLE OF TRANS_OBJ;
CREATE OR REPLACE FUNCTION TEST2 (v_rc IN SYS_REFCURSOR) RETURN TRANS_OBJ_TAB
IS
v_resp TRANS_OBJ_TAB := TRANS_OBJ_TAB();
BEGIN
v_resp.extend;
v_resp(1) := TRANS_OBJ('222222');
RETURN v_resp;
END;
CREATE OR REPLACE FUNCTION TEST1 RETURN TRANS_OBJ_TAB
IS
TRANSNO CHAR(8);
v_cnt number := 0;
v_req TRANS_OBJ_TAB := TRANS_OBJ_TAB();
v_resp TRANS_OBJ_TAB := TRANS_OBJ_TAB();
--v_resp sys_refcursor;
CURSOR v_rc IS SELECT '1111' AS TRANSNO FROM DUAL;
BEGIN
OPEN v_rc;
LOOP
fetch v_rc into TRANSNO;
EXIT WHEN v_rc%NOTFOUND;
v_req.extend;
v_cnt := v_cnt + 1;
v_req(v_cnt) := TRANS_OBJ(TRANSNO);
END LOOP;
CLOSE v_rc;
v_resp := TEST2(v_req);
RETURN v_resp;
END;
/
DROP TYPE TRANS_OBJ_TAB;
DROP TYPE TRANS_OBJ;
DROP FUNCTION TEST1;
DROP FUNCTION TEST2;
First you are not returning a CURSOR from TEST2 function as you says (try return sys_refcursor).
On the other hand v_req is not an sys_refcursor, besides v_resp can't contains a cursor too. Review the types you are using.
Hope this help!!!

PLS-00103 error while creating package with overloading functions

Please help in finding the error while creating the package with overloading functions.
Error shown:
PL-00103: Encountered the symbol "NUMOU"when expecting one of the following: language.
PL-00103: Encountered the symbol "Function" when expecting one of the following: end not pragma final instantiable order overriding static member constructor map.
code:
create or replace package over_load as
function print_it(numin varchar2) return number is numou number;
begin
numou := to_number(numin, '999,999.00');
dbms_output.put_line(numou);
return numou;
exception
when others then
dbms_output.put_line('Wrong string format');
return numou;
end;
function print_it(datin date) return varchar2 is datout varchar2(30);
dumcha varchar2(30);
dumdat date;
begin
dumcha := to_char(datin);
dumdat := to_date(dumcha,'FXDD-MON-YYYY');
datout := to_char(datin, 'fmMOn, DD YYYY');
dbms_output.put_line(datout);
return datout;
Exception
when others then
dbms_output.put_line('Wrong input date format');
return '0';
end;
end;
In Oracle RDBMS You MUST specify package (for public methods) and package body containing implementation for all public methods and optionally You can add some private methods.
Package specification:
create or replace package over_load as
function print_it(numin varchar2) return number;
function print_it(datin date) return varchar2;
end;
And body:
create or replace package body over_load as
function print_it(numin varchar2) return number is
numou number;
begin
numou := to_number(numin, '999,999.00');
dbms_output.put_line(numou);
return numou;
exception
when others then
dbms_output.put_line('Wrong string format');
return numou;
end;
function print_it(datin date) return varchar2 is
datout varchar2(30);
dumcha varchar2(30);
dumdat date;
begin
dumcha := to_char(datin);
dumdat := to_date(dumcha,'FXDD-MON-YYYY');
datout := to_char(datin, 'fmMOn, DD YYYY');
dbms_output.put_line(datout);
return datout;
exception
when others then
dbms_output.put_line('Wrong input date format');
return '0';
end;
end;
NOTE THAT:
To enable output from DBMS_OUTPUT in SQL*Plus You must enable serveroutput:
SQL> set serveroutput on size 30000;

Resources