Oracle Reference to uninitialized composite while passing object as output parameter PL/SQL - oracle

I have a problem with "ORA-06530: Reference to uninitialized composite". The object is as far as I understand initialiazed.
CREATE OR REPLACE TYPE t_RetVal AS OBJECT
(
var_n_retVal NUMBER,
var_n_sqlcode NUMBER,
var_v_sqlerrm VARCHAR(255),
CONSTRUCTOR FUNCTION t_RetVal(SELF IN OUT NOCOPY t_RetVal) RETURN SELF AS RESULT
);
/
CREATE OR REPLACE TYPE BODY t_RetVal AS
CONSTRUCTOR FUNCTION t_RetVal(SELF IN OUT NOCOPY t_RetVal) RETURN SELF AS RESULT IS
BEGIN
SELF.var_n_retVal := 1;
SELF.var_n_sqlcode := 0;
SELF.var_v_sqlerrm := '';
RETURN;
END;
END;
create or replace FUNCTION get_Something(
id IN NUMBER,
out_t_RetVal OUT NOCOPY t_RetVal
)
RETURN NUMBER
IS
retVal NUMBER := 1;
BEGIN
out_t_RetVal.var_n_retVal:= 1;
out_t_RetVal.var_n_sqlcode := 0;
out_t_RetVal.var_v_sqlerrm := '';
RETURN out_t_RetVal;
END;
In the procedure i do the following and keep getting "ORA-06530: Reference to uninitialized composite".
create or replace procedure PROC is
var_t_SubFuncRetVal t_RetVal;
v_n_retVal number := 0;
v_error_text varchar2(1000);
BEGIN /*PROCEDURE START*/
var_t_SubFuncRetVal := t_RetVal();
v_n_retVal := get_Something( id, var_t_SubFuncRetVal);
IF (var_t_SubFuncRetVal.var_n_retVal >= 0) THEN
IF (var_t_SubFuncRetVal.var_n_retVal = 0) THEN
....
ELSE
....
END IF;
ELSE
v_error_text := 'Error message is '|| 'SQLCODE: '||var_t_SubFuncRetVal.var_n_sqlcode||' -- ERROR: '||var_t_SubFuncRetVal.var_v_sqlerrm;
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END PROC;
Why is Oracle reporting this error ? How to properly pass object as out parameter ?

Related

Comparing data of any type without overloading

let's start with an example:
type Collection_t is table of varchar2(3);
Collection_v Collection_t := Collection_t('qwe', 'asd', 'yxc', 'rtz', 'fgh', 'vbn');
single_var varchar2(3) := 'yxc';
procedure get_position(Single_Value varchar2, Value_Set Collection_t) is
i integer := 1;
begin
while (i is not null) loop
if Single_Value = Value_Set(i)
then
dbms_output.put_line(i);
end if;
i := Value_Set.Next(i);
end loop;
end;
begin
get_position(single_var, Collection_v);
end;
now, question is: can I declare this procedure with 'anydata', and check if table (2ed argument) consists of the same type as first argument.
I'd assume declaration of a procedure would look like that:
procedure get_position(Single_Value anydata, Value_Set anydata) is ...
later I'd compare types, and honestly I couldn't figure it out, how to solve this problem.
From my limited understanding, you still have to encode/decode anydata into basic (or user-defined) PL/SQL types to do anything meaningful like comparing values, so you might not gain the benefits of dynamic languages like Python.
Here is an example, passing anydata as a parameter. You'll need to update anydata_to_varchar to handle data types you need.
Personally, overloading seems like a more straightforward approach, unless there is a better way to work with anydata values.
declare
type tab_anydata is table of anydata;
-- test as varchar2
/*
lookup_array tab_anydata := tab_anydata(
anydata.convertVarchar2('blah'),
anydata.convertVarchar2('meh'),
anydata.convertVarchar2('foo'),
anydata.convertVarchar2('bar')
);
lookup_value anydata := anydata.convertVarchar2('foo');
*/
-- test as date
lookup_array tab_anydata := tab_anydata(
anydata.convertDate(trunc(sysdate - 2)),
anydata.convertDate(trunc(sysdate - 0)),
anydata.convertDate(trunc(sysdate + 1)),
anydata.convertDate(trunc(sysdate + 2))
);
lookup_value anydata := anydata.convertDate(trunc(sysdate));
function anydata_to_varchar(p_what anydata)
return varchar2
is
value_type varchar2(30) := anydata.GetTypeName(p_what);
result varchar2(32767);
begin
select
case value_type
when 'SYS.VARCHAR2' then anydata.AccessVarchar2(p_what)
when 'SYS.DATE' then to_char(anydata.AccessDate(p_what), 'YYYY-MM-DD')
when 'SYS.NUMBER' then to_char(anydata.AccessNumber(p_what))
else null
end into result
from dual;
return result;
end;
function get_position(p_what anydata, p_where tab_anydata)
return number
is
pos number := -1;
what_value varchar2(30) := anydata_to_varchar(p_what);
curr_value varchar2(30);
begin
for i in 1..p_where.count
loop
curr_value := anydata_to_varchar(p_where(i));
if what_value = curr_value then
pos := i;
exit;
end if;
end loop;
return pos;
end;
begin
dbms_output.put_line('lookup type : '||anydata.GetTypeName(lookup_value));
dbms_output.put_line('lookup value : '||anydata_to_varchar(lookup_value));
dbms_output.put_line('found position: '||get_position(lookup_value, lookup_array));
end;
/
dbms_output:
lookup type : SYS.DATE
lookup value : 2022-07-20
found position: 2
db<>fiddle here

Wrong number or TYPES of arguments, error in PL/SQL

I have to create a list of RECORD and I need to send it to a procedure.
There is my header.
CREATE OR REPLACE PACKAGE tema4 IS
TYPE obj IS RECORD(id INTEGER := 0,percent INTEGER := 0);
TYPE listObj IS TABLE OF obj INDEX BY PLS_INTEGER;
PROCEDURE ex1 (p_listObj IN listObj);
END tema4;
My body.
create or replace PACKAGE BODY tema4 IS
PROCEDURE ex1 (p_listObj IN listObj) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Cant reach');
END ex1;
END tema4;
And my code that calls procedure ex1.
DECLARE
TYPE obj IS RECORD(id INTEGER := 0,percent INTEGER := 0);
TYPE listObj IS TABLE OF obj INDEX BY PLS_INTEGER;
v_obj obj;
v_listObj listObj;
BEGIN
FOR v_i IN (SELECT ID,BURSA FROM STUDENTI ORDER BY ID) LOOP
v_obj.id := v_i.id;
v_obj.percent := 50;
v_listObj(v_i.id) := v_obj;
END LOOP;
FOR v_i IN v_listObj.FIRST..v_listObj.LAST LOOP
DBMS_OUTPUT.PUT_LINE(v_listObj(v_i).id || ' - ' ||
v_listObj(v_i).percent);
END LOOP;
tema4.ex1(v_listObj); --this line is with problems
END;
PLS-00306: wrong number or types of arguments in call to 'EX1'
Can someone explain me what is wrong in my code? I also tried to create my type as global, but it won't let me because of 'RECORD' keyword.
Don't declare the types again (new types), use the types already declared in the package spec:
DECLARE
v_obj tema4.obj;
v_listObj tema4.listObj;
BEGIN
FOR v_i IN (SELECT ID,BURSA FROM STUDENTI ORDER BY ID) LOOP
v_obj.id := v_i.id;
v_obj.percent := 50;
v_listObj(v_i.id) := v_obj;
END LOOP;
FOR v_i IN v_listObj.FIRST..v_listObj.LAST LOOP
DBMS_OUTPUT.PUT_LINE(v_listObj(v_i).id || ' - ' ||
v_listObj(v_i).percent);
END LOOP;
tema4.ex1(v_listObj); --this line is with problems
END;

Where in stored procedure I can make exit status?

I have oracle stored procedure where i check sender I'd,source system, and transaction number at the beginning of the procedure. Can I do it this way:
If Id != "aaa"
Exit -1;
Else if source = " ".
Exit -1;
Else if trans = " ".
Exit -1;
Else.
-- continues stored procedure
I appreciate any help
To rephrase your question more generally, you want a caller of your routine to know if something bad has happened inside it. There are (at least) three ways of doing this in PL/SQL.
Use an OUT parameter
Procedure cannot return a value, the way a function does, but it can set an output parameter:
CREATE PROCEDURE inner (p_id IN VARCHAR2(10), p_res OUT NUMBER)
IS
BEGIN
p_res := 0; -- default value
IF p_id = 'aaa' THEN
p_res := -1;
RETURN;
ELSE
-- do something
END IF;
END;
Then in the caller you would have:
DECLARE res NUMBER;
...
inner('aaa', res);
IF res = -1 THEN
-- panic!
END IF;
...
Use a function
Despite your seeming aversion to functions, this might be an option.
CREATE FUNCTION inner (p_id IN VARCHAR2(10))
RETURN NUMBER
IS
BEGIN
IF p_id = 'aaa' THEN
RETURN -1;
END IF;
-- do something
RETURN 0;
END;
Then in the caller:
...
IF inner('aaa') = -1 THEN
-- panic!
END IF;
...
Use an exception
Similar to other programming languages, PL/SQL has exceptions:
CREATE PROCEDURE inner (p_id IN VARCHAR2(10))
IS
BEGIN
IF p_id = 'aaa' THEN
RAISE_APPLICATION_ERROR(-20000, 'ID cannot be ''aaa''');
ELSE
-- do something
END IF;
END;
and in the caller:
...
DECLARE
panic EXCEPTION; -- declare exception
PRAGMA EXCEPTION_INIT (panic, -20000); -- assign error code to exception
...
BEGIN
inner ('aaa');
EXCEPTION
WHEN panic THEN
-- proceed to panic
END;
You are using a wrong syntax both for the IF...ELSE and for the exit.
Given that you are saying you need to get a return value, you probably need a function like this, using CASE:
create or replace function testFun ( pIn1 varchar2, pIn2 varchar2) return varchar2 is
begin
case
when pIn1 is null then
return -1;
when pIn2 = ' ' then
return -2;
else
return 999;
end case;
end;

how to daclare queue data-structure in oracle?

is There Any Way to Declare a Queue Data Structure Which be Accessible Globally in Oracle or in a Specific Schema?
With Globally i Mean be Accessible in All Procedures of Database or Specific Schema
edited :
i find out i can make FIFO QUEUE by package. so i wrote a code but i get error. any one know why i get this error?
package spec:
CREATE OR REPLACE PACKAGE HR.TEST_PACKAGE IS
PROCEDURE ADDQ (TABLE_NAME VARCHAR2);
FUNCTION DELQ RETURN VARCHAR2;
END TEST_PACKAGE;
/
package body:
CREATE OR REPLACE PACKAGE BODY HR.TEST_PACKAGE IS
REAR NUMBER := 0;
FRONT NUMBER := 0;
TYPE QUEUE_TYPE IS VARRAY(10) OF VARCHAR2(15);
QUEUE_ARRAY QUEUE_TYPE;
PROCEDURE ADDQ (TABLE_NAME VARCHAR2) IS
BEGIN
REAR := (REAR+1) MOD 10;
IF (REAR = 0) THEN
REAR := 10;
END IF;
QUEUE_ARRAY(REAR) := TABLE_NAME;
END ADDQ;
FUNCTION DELQ RETURN VARCHAR2 IS
BEGIN
IF (FRONT = REAR) THEN
RETURN 'EMPTY';
ELSE
FRONT := (FRONT + 1) MOD 10;
IF (FRONT = 0) THEN
front := 10;
END IF;
RETURN QUEUE_ARRAY(FRONT);
END IF;
END DELQ;
END TEST_PACKAGE;
/
when i run this example code:
create or replace procedure hr.test is
begin
hr.test_package.addq('a');
hr.test_package.addq('b');
dbms_output.put_line(hr.test_package.delq);
end test;
i get this error:
ORA-06531: Reference to uninitialized collection
06531. 00000 - "Reference to uninitialized collection"
*Cause: An element or member function of a nested table or varray
was referenced (where an initialized collection is needed)
without the collection having been initialized.
*Action: Initialize the collection with an appropriate constructor
or whole-object assignment.
and this error occur when wants to run this part of a code:
QUEUE_ARRAY(REAR) := TABLE_NAME;
Problem Solved. following code will declare a FIFO QUEUE in oracle.
the addq procedure will insert in queue and delq function will delete and return a value from queue.
package spec:
CREATE OR REPLACE PACKAGE HR.TEST_PACKAGE IS
PROCEDURE ADDQ (TABLE_NAME VARCHAR2);
FUNCTION DELQ RETURN VARCHAR2;
END TEST_PACKAGE;
/
package body:
CREATE OR REPLACE PACKAGE BODY HR.TEST_PACKAGE IS
REAR NUMBER := 0;
FRONT NUMBER := 0;
TYPE QUEUE_TYPE IS VARRAY(10) OF VARCHAR2(15);
QUEUE_ARRAY QUEUE_TYPE := QUEUE_TYPE() ;
PROCEDURE ADDQ (TABLE_NAME VARCHAR2) IS
BEGIN
REAR := (REAR+1) MOD 10;
IF (REAR = 0) THEN
REAR := 10;
END IF;
QUEUE_ARRAY.EXTEND;
QUEUE_ARRAY(REAR) := TABLE_NAME;
END ADDQ;
FUNCTION DELQ RETURN VARCHAR2 IS
BEGIN
IF (FRONT = REAR) THEN
RETURN 'EMPTY';
ELSE
FRONT := (FRONT + 1) MOD 10;
IF (FRONT = 0) THEN
front := 10;
END IF;
RETURN QUEUE_ARRAY(FRONT);
END IF;
END DELQ;
END TEST_PACKAGE;
/

'Reference to uninitialized composite' while trying to execute a stored procedure in Oracle with UDTs

There is this package and I am trying to execute using the code below. However I get an error
ORA-06530: Reference to uninitialized composite
Code:
DECLARE
StudyNum InputTyp := InputTyp ();
StudyDetails OutputTyp := OutputTyp ();
BEGIN
StudyNum.EXTEND;
StudyNum (1) := '9071';
my_package.my_procedure(StudyNum, StudyDetails);
END;
/
The package is created as below with user-defined datatypes as input & output params:
Create OR REPLACE Type InputTyp AS VARRAY(200) OF VARCHAR2 (1000);
CREATE TYPE OBJTYP AS OBJECT
(
A NUMBER,
B VARCHAR2 (1000),
C VARCHAR2 (100)
);
CREATE TYPE OutputTyp IS VARRAY (2000) OF OBJTYP;
/
CREATE OR REPLACE PACKAGE my_package
AS
PROCEDURE my_procedure(p_StudyNum IN InputTyp,p_StdyDtl OUT OutputTyp);
END my_package;
/
CREATE OR REPLACE PACKAGE BODY my_package
AS
PROCEDURE my_procedure(p_StudyNum IN InputTyp,p_StdyDtl OUT OutputTyp)
IS
i BINARY_INTEGER := 1;
j BINARY_INTEGER := 1;
CURSOR c_StudyTbl
IS
SELECT A, B, C
FROM my_table
WHERE Study_Number = p_StudyNum(i);
v_StudyTbl OBJTYP;
BEGIN
p_StdyDtl := OutputTyp ();
LOOP
-- This is the first cursor opened for each of the items in the list.
EXIT WHEN i > p_StudyNum.count;
OPEN c_StudyTbl;
LOOP
FETCH c_StudyTbl INTO v_StudyTbl;
EXIT WHEN c_StudyTbl%NOTFOUND;
p_StdyDtl.EXTEND ();
p_StdyDtl (j).A := v_StudyTbl.A;
p_StdyDtl (j).B := v_StudyTbl.B;
p_StdyDtl (j).C := v_StudyTbl.C;
j := j + 1;
END LOOP;
CLOSE c_StudyTbl;
i := i + 1;
END LOOP;
IF c_StudyTbl%ISOPEN
THEN
CLOSE c_StudyTbl;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
END;
END my_package;
/
you would either need to do :
p_StdyDtl(p_StdyDtl.last) := OBJTYP(null, null, null);
p_StdyDtl (j).A := v_StudyTbl.A;
p_StdyDtl (j).B := v_StudyTbl.B;
p_StdyDtl (j).C := v_StudyTbl.C;
or simpler:
p_StdyDtl(j) := OBJTYP(v_StudyTbl.A, v_StudyTbl.B, v_StudyTbl.C);
your code as-is fails because you've initialised the OutputTyp but not the objtyp part.
but as I said in the prior question of yours, the multiset avoids all of that.

Resources