How to drop overloaded functions in Oracle? - oracle

I have faced this question during an interview very recently. Please hep me on this. Let us say there are two functions in our schema the prototypes of which are as follows,
display(a varchar2, b number)
display(c varchar2, d varchar2, e number)
and I issue the following statement
drop function display;
which function will be dropped?

overloading means use of same subprograms to call different subprograms. this is an example
declare
x number;
y number;
function findenqno (fname1 varchar2) return number is --–function 1
enqno1 number (10);
begin
select enquiryno
into enqno1
from enquiry
where fname = fname1;
return(enqno1);
end;
function findenqno (refcode1 number) return number is --–function 2
enqno1 number (10);
begin
select enquiryno
into enqno1
from enquiry
where refcode = refcode1;
return (enqno1);
end;
begin
-- You call the function as:
X := findenqno ('ANIL');
dbms_output.put_line('using name '||x);
Y := findenqno (1002);
dbms_output.put_line('using refcode '||y);
end;
/
this is not a standlone subprogram so there is no point droping a overloaded function .
as it is not written in the db.

Related

Trying to call a Function inside a stored procedure in oracle

i am trying to call a function from stored procedure in Oracle, but not getting any idea how to do.
my function has two IN parameter and one OUT parameter.
in my procedure i am using out sys refcursor . Any refrence or example will help me a lot.
Here is a simple example for calling function inside procedure. Also as mentioned by APC using OUT in function is a bad practice. Instead you can return your required output. And I'm not sure how you are using sys_refcursor, so modify your procedure accordingly
CREATE OR REPLACE FUNCTION SUM_OF_2(NUM1 IN NUMBER,NUM2 IN NUMBER) RETURN NUMBER
IS
RESULT_SUM NUMBER;
BEGIN
RESULT_SUM:=NUM1+NUM2;
RETURN RESULT_SUM;
END;
CREATE OR REPLACE PROCEDURE CALL_FUNCTON(NUM1 NUMBER,NUM2 NUMBER)
AS
V_FINAL_RESULT NUMBER;
BEGIN
V_FINAL_RESULT:=SUM_OF_2(NUM1,NUM2);
DBMS_OUTPUT.PUT_LINE(V_FINAL_RESULT);
END;
BEGIN
CALL_FUNCTON(5,10);
END;
/
CHECK DEMO HERE
Not sure on what your requirement is , maybe you are just trying the code for education purposes. Generally I have not seen much code which uses OUT parameter with functions, in case you want to return multiple values to the caller object then you could use a procedure with more then one OUT variables. There are some limitation on how an oracle function with OUT parameter would differ from a normal function.
CREATE OR REPLACE FUNCTION temp_demo_func(out_var1 OUT NUMBER)
RETURN VARCHAR2 IS
BEGIN
out_var1 := 1;
RETURN 'T';
EXCEPTION
WHEN OTHERS THEN
RETURN 'F';
END temp_demo_func;
/
CREATE OR REPLACE PROCEDURE temp_demo_proc
(
in_var1 NUMBER
,cur_refcur_out OUT SYS_REFCURSOR
) IS
res VARCHAR2(1);
out_var1 NUMBER;
BEGIN
res := temp_demo_func(out_var1 => out_var1);
dbms_output.put_line(out_var1);
OPEN cur_refcur_out FOR
SELECT in_var1
,out_var1
,res
FROM dual;
END;
/
set serveroutput on
declare
cur_refcur_out Sys_Refcursor;
in_var1 number := 22;
begin
temp_demo_proc(in_var1 => in_var1
,cur_refcur_out => cur_refcur_out);
end;
/

Calling procedure in function

Can you call a PL/SQL procedure from inside a function?
I haven't come across with the practical example.So if anyone has come across with this please share.
Yes. You can call any pl/sql program from inside any other pl/sql program. A function can call a function, a procedure can call a procedure which calls a function, a function can invoke a TYPE BODY...do an INSERT..which causes a TRIGGER to fire.
A simple (not really practical) example.
Using the HR schema where you have an EMPLOYEES table which includes columns EMPLOYEE_ID, FIRST_NAME, and LAST_NAME.
I have a function that takes in an INTEGER which we use to look up an EMPLOYEE record. We take their first and last names, and concat them together, and return the value back in UPPERCASE text.
Before we do that however, we call a procedure which does nothing but take a 5 second nap using the DBMS_LOCK package.
The code:
create or replace procedure do_nothing_comments (x in integer, y in integer)
is
begin
null;
-- yeah, this is a dumb demo
dbms_lock.sleep(5);
end;
/
create or replace FUNCTION upper_name (
x IN INTEGER
) RETURN VARCHAR2 IS
upper_first_and_last VARCHAR2 (256);
BEGIN
SELECT upper (first_name)
|| ' '
|| upper (last_name)
INTO upper_first_and_last
FROM employees
WHERE employee_id = x;
do_nothing_comments (1, 2); -- here we are calling the procedure
RETURN upper_first_and_last;
END;
/
Now let's invoke the function.
DECLARE
X NUMBER;
v_Return VARCHAR2(200);
BEGIN
X := 101;
v_Return := UPPER_NAME(
X => X
);
:v_Return := v_Return;
END;
/
I'm going to do this in SQL Developer using the Execute feature with the function open:
I get the answer back...it just takes 5 seconds longer than it really needed to.
Here you go:
create or replace function demo
return varchar2
as
begin
dbms_output.put_line('Hello');
return 1;
end demo;

PLS-00201: identifier must be declared in Procedure

I have a PL/SQL Procedure code, which runs when it is / , but doesn't runs when it's executed. The error message I get is
SQL> EXECUTE MAXINUM;
BEGIN MAXINUM; END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00201: identifier 'MAXINUM' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
The code which I'm working on is :
DECLARE
N NUMBER;
M NUMBER;
O NUMBER;
P NUMBER;
X NUMBER;
PROCEDURE MAXINUM(N IN NUMBER, M IN NUMBER, O IN NUMBER, P IN NUMBER, X OUT NUMBER) IS
BEGIN
IF N>M AND N>O AND N>P THEN
X:=N;
ELSIF M>N AND M>O AND M>P THEN
X:=M;
ELSIF O>N AND O>M AND O>P THEN
X:=O;
ELSIF P>N AND P>M AND P>O THEN
X:=P;
END IF;
END;
BEGIN
N:=&NUMBER;
M:=&NUMBER;
O:=&NUMBER;
P:=&NUMBER;
MAXINUM(N,M,O,P,X);
DBMS_OUTPUT.PUT_LINE('HIGHEST NUMBER = '||X);
END;
/
When it gave the 'identifier error', I tried dropping this procedure I got the error:
SQL> DROP PROCEDURE MAXINUM;
DROP PROCEDURE MAXINUM
*
ERROR at line 1:
ORA-04043: object MAXINUM does not exist
I have so far read this, this, this solutions and other solutions some what related to this error.
You have written an anonymous block with a local procedure MAXINUM(). This procedure can be called within that block but does not exist outside that block. Consequently you cannot call it independently.
If you want to use the procedure elsewhere you need to create it as a first class database object:
create or replace procedure MAXINUM
(N IN NUMBER, M IN NUMBER, O IN NUMBER, P IN NUMBER, X OUT NUMBER)
is
BEGIN
IF N>M AND N>O AND N>P THEN
X:=N;
ELSIF M>N AND M>O AND M>P THEN
X:=M;
ELSIF O>N AND O>M AND O>P THEN
X:=O;
ELSIF P>N AND P>M AND P>O THEN
X:=P;
END IF;
END;
/
Now you can call it in your code, like this:
DECLARE
N NUMBER;
M NUMBER;
O NUMBER;
P NUMBER;
X NUMBER;
BEGIN
N:=&NUMBER;
M:=&NUMBER;
O:=&NUMBER;
P:=&NUMBER;
MAXINUM(N,M,O,P,X);
DBMS_OUTPUT.PUT_LINE('HIGHEST NUMBER = '||X);
END;
/
Points to note:
what happens if a parameter is null?
what happens if two arguments have the same value?
the convention would be to declare this as a function and return the highest value instead of setting an OUT parameter.
Incidentally I assume you're doing this as an exercise, as it is a re-implementation of an existing Oracle built-in function, greatest().

too many declarations of

I am getting the following error message while running the below code. I am new to coding world of pl/sql (oracle) and I request your assistance for the same.
Code:
create or replace package learn is
function Area(i_rad NUMBER) return NUMBER;
function Area(i_length NUMBER, i_width NUMBER:=3) return NUMBER;
end;
/
Package body:
create or replace package body learn is
function Area(i_rad NUMBER) return NUMBER
is
v_pi NUMBER:=3.14;
v number:=to_number(i_rad);
begin
return v_pi * (i_rad ** 2);
end;
function Area(i_length NUMBER, i_width NUMBER:=3) return NUMBER
is
begin
return i_length * i_width;
end;
end learn;
Plsql block
declare
x number(2):=2;
y number(2):=5;
begin
DBMS_OUTPUT.put_line('Area (R=3):'||learn.Area(x));
DBMS_OUTPUT.put_line('Area (R=3):'||learn.Area(x,y));
end;
Error Message: too many declarations of 'AREA' match this call
That's because you have default value for the second parameter in your two param function. If you provide only param, the second function will assume the second value to be 3 and now there are two functions that can be called and hence the call failed.
I'd suggest you not to do this kind of overloading as it is not clear which function does what.
If you still want to do this, one way is to make the second param mandatory and pass null if you don't have any value to pass.
create or replace package learn is
function Area(i_rad NUMBER) return NUMBER;
function Area(i_length NUMBER, i_width NUMBER) return NUMBER;
end;
/
create or replace package body learn is
function Area(i_rad NUMBER) return NUMBER
is
v_pi NUMBER:=3.14;
v number:=to_number(i_rad);
begin
return v_pi * (i_rad ** 2);
end;
function Area(i_length NUMBER, i_width NUMBER) return NUMBER
is
begin
return i_length * nvl(i_width,3);
end;
end learn;
/
declare
x number(2):=2;
y number(2):=5;
begin
DBMS_OUTPUT.put_line('Area (R=3):'||learn.Area(x));
DBMS_OUTPUT.put_line('Area (R=3):'||learn.Area(x,y));
end;
/
If you have different param names, you can do this:
declare
x number(2):=2;
y number(2):=5;
begin
DBMS_OUTPUT.put_line('Area (R=3):'||learn.Area(i_rad => x));
DBMS_OUTPUT.put_line('Area (R=3):'||learn.Area(x,y));
end;
/
Since i_width has a default value, you have two functions that can be called with a single number argument. Since both these functions calculate different areas, a good way to differentiate would be to simply use different names:
CREATE OR REPLACE PACKAGE learn IS
FUNCTION circle_area(i_rad NUMBER) RETURN NUMBER;
FUNCTION rectangle_area(i_length NUMBER, i_width NUMBER:=3) RETURN NUMBER;
-- And the same changes in the package body, of course.
END;
/

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

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;

Resources