too many declarations of - oracle

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;
/

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;

How to drop overloaded functions in 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.

How to debug a user defined aggregate function in Oracle 11g?

I'm trying to learn how to create a user defined aggregate function. So far, I've been able to create one that compiles fine, but calling it gives an unexpected result. The function is a very simple test function that looks through a number of rows that are either set to 'Y' or 'N' and returns 'Y' if all are set to 'Y' and otherwise returns 'N'. I'm running it on a single row and getting back a blank varchar 2 instead.
I'm not sure what is the procedure to go through with debugging this. I've tried using DBMS_OUTPUT.PUT_LINE(), but I cannot see anything on the database output. The largest problem is that it is creating the function fine, and most of the code is in an object type. Thus, if I were to try to debug the select statement, it is calling code on the database that has already been compiled.
Below is the code for the function, but I don't want to know why this isn't working as much as I want to know how to debug so I can solve these issues myself, especially when more complex aggregate functions are involved.
CREATE OR REPLACE TYPE MYSCHEMA.ALL_TRUE_T AS OBJECT
(
TRUE_SO_FAR VARCHAR2(1),
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT ALL_TRUE_T) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT ALL_TRUE_T, value IN VARCHAR2) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateTerminate(self IN ALL_TRUE_T, returnValue OUT VARCHAR2, flags IN NUMBER) RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateMerge(self IN OUT ALL_TRUE_T, ctx2 IN ALL_TRUE_T) RETURN NUMBER
);
CREATE OR REPLACE TYPE BODY MYSCHEMA.ALL_TRUE_T IS
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT ALL_TRUE_T)
RETURN NUMBER IS
BEGIN
sctx := ALL_TRUE_T('Y');
return ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT ALL_TRUE_T, value IN VARCHAR2)
RETURN NUMBER IS
BEGIN
IF value <> 'Y' OR self.TRUE_SO_FAR <> 'Y' THEN
self.TRUE_SO_FAR := 'N';
END IF;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate(self IN ALL_TRUE_T, returnValue OUT VARCHAR2, flags IN NUMBER)
RETURN NUMBER IS
BEGIN
returnValue := self.TRUE_SO_FAR;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateMerge(self IN OUT ALL_TRUE_T, ctx2 IN ALL_TRUE_T)
RETURN NUMBER IS
BEGIN
IF ctx2.TRUE_SO_FAR = 'N' THEN
self.TRUE_SO_FAR := 'N';
END IF;
RETURN ODCIConst.Success;
END;
END;
CREATE OR REPLACE PACKAGE MYSCHEMA.ALL_TRUE_PKG IS
FUNCTION ALL_TRUE (input VARCHAR2) RETURN VARCHAR2;
END;
CREATE OR REPLACE PACKAGE BODY MYSCHEMA.ALL_TRUE_PKG IS
FUNCTION ALL_TRUE (input VARCHAR2) RETURN VARCHAR2
AGGREGATE USING ALL_TRUE_T;
END;
And here is how I call it. YN_TEST_TABLE currently has a single row with an 'N' in it.
SELECT
MYSCHEMA.ALL_TRUE_PKG.ALL_TRUE(YN)
FROM
MYSCHEMA.YN_TEST_TABLE
Finally, I'm not sure if this is relevant, but I'm using Toad 11.6.
Edit:
So I've tried inserting into a temp log table and that didn't work either.
I added the following
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT ALL_TRUE_T, value IN VARCHAR2)
RETURN NUMBER IS
BEGIN
BEGIN
INSERT INTO MYSCHEMA.LAWTONFOGLES_TEMP_LOG
(
ID,
Message,
Time
)
VALUES
(
'all_true',
'test1',
systimestamp
);
END;
IF value <> 'Y' OR self.TRUE_SO_FAR <> 'Y' THEN
self.TRUE_SO_FAR := 'N';
END IF;
RETURN ODCIConst.Success;
END;
There was nothing in the temp log, but also no error message. It is as if none of the 4 aggregate function parts are even being called.
EDIT2:
So, to make things more interesting, this works when it is not in a package.
I did the following
CREATE OR REPLACE FUNCTION MYSCHEMA.LAWTONFOGLES_ALL_TRUE (input VARCHAR2) RETURN VARCHAR2
AGGREGATE USING ALL_TRUE_T;
and then ran this
SELECT
MYSCHEMA.LAWTONFOGLES_ALL_TRUE(YN)
FROM
MYSCHEMA.YN_TEST_TABLE
and got the results I expected. It seems that the code itself isn't a problem, but putting it in a package causes it to break. Thursday my Oracle DBA will be opening a ticket up with oracle, so I'll be sure to update with why does putting this in a package break it but leaving it as just a function doesn't when they get back with us. Until then I may just have to keep this outside of a package.
Also, I tried to add a put_line on it when it was working and still did not get an output. I think that the way user defined aggregate functions work prevent put_line from working.
If you're using TOAD, be sure to turn on DBMS_OUTPUT recording before you run your proc so you can see your outputs. It should be on the bottom DBMS tab (if you have it open). Typically you'll see a red circle since it's defaulted as off. Click the circle so that it's green.
See this link as an example: http://geekbrigade.wordpress.com/2009/04/09/how-to-set-and-view-dbms-output-of-oralce-in-toad/

Issue with Oracle user-defined aggregate functions

I'm having this annoying issue with aggregate udfs where it always fails to invoke the iteration method. My code is just like the other examples around the web (including the ones on oracle docs and asktom). I tried to change the UDF type and the same happens everytime. It says:
ORA-29925: cannot execute DBAODB.WMCONCATROUTINES.ODCIAGGREGATEITERATE
ORA-06553: PLS-306: wrong number or types of arguments in call to 'ODCIAGGREGATEITERATE'
Oracle version is 11.1.0.7.0 and Here's my code:
CREATE OR REPLACE TYPE WmConcatRoutines as object (
tmpData number,
STATIC FUNCTION ODCIAggregateInitialize( wmInst IN OUT WmConcatRoutines) RETURN number,
MEMBER FUNCTION ODCIAggregateIterate(wmInst IN OUT WmConcatRoutines, value number) return number,
MEMBER FUNCTION ODCIAggregateMerge(wmInst IN OUT WmConcatRoutines, wmInst2 IN WmConcatRoutines) return number,
MEMBER FUNCTION ODCIAggregateTerminate(wmInst IN WmConcatRoutines, returnValue OUT number, flags IN number) return number
);
/
CREATE OR REPLACE TYPE BODY WmConcatRoutines IS
STATIC FUNCTION ODCIAggregateInitialize( wmInst IN OUT WmConcatRoutines) RETURN number IS
BEGIN
wmInst := WmConcatRoutines(0);
return ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateIterate(wmInst IN OUT WmConcatRoutines, value number) return number IS
BEGIN
wmInst.tmpData := wmInst.tmpData + value;
return ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate(wmInst IN WmConcatRoutines, returnValue OUT number, flags IN number) return number IS
BEGIN
returnValue := wmInst.tmpData;
return ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateMerge(wmInst IN OUT WmConcatRoutines, wmInst2 IN WmConcatRoutines) return number IS
BEGIN
wmInst.tmpData := wmInst.tmpData + wmInst2.tmpData;
return ODCIConst.Success;
END;
END;
/
CREATE OR REPLACE FUNCTION WM_CONCAT_test (input number) RETURN number
parallel_enable
AGGREGATE USING WmConcatRoutines;
/
Any ideas on what may be causing this? thanks in advance
The parameter names in your implementations of the ODCI functions have to match those in the documentation; so you have to use sctx, self, and ctx2 rather than wminst and wminst2.
Edit As APC briefly mentioned, it only seems to be self that is required; you can use something else in place of sctx and ctx2. I can't find a documentation reference...
Edit 2 Yes, I can... APC's reference to it being an object thing led me to this.

Resources