How can i use REF type in PL/SQL Oracle? - oracle

I have this code :
CREATE OR REPLACE TYPE t_abonnement_type AS OBJECT
(
ref_abonnement_type NUMBER,
type_abonne VARCHAR(50),
MEMBER PROCEDURE DISPLAY
);
CREATE OR REPLACE TYPE t_abonnement AS OBJECT
(
ref_abonnement NUMBER,
date_debut DATE,
type_abonnement REF t_abonnement_type,
MEMBER PROCEDURE DISPLAY
);
What i want to do is just create the members procedures DISPLAY declared.
So i did it this way :
CREATE OR REPLACE TYPE BODY t_abonnement AS
MEMBER PROCEDURE DISPLAY IS
BEGIN
/* SOME CODE */
type_abonnement.display;
END;
END;
And i get this error
PLS-00536: Navigation through REF variables is not supported in PL/SQL.
So how can i deal with REF in PL/SQL statements ?
Thanks

As mentioned by #APC, it's not possible to directly use member function of a Object to another using REF since Oracle supports them in SQL but not in PL/SQL.
However if I look at your requirement from a different angle, I could see you are trying to simply make use of Procedure used in an Object to another Object. Means if I forget the referencing part and create a scenario which could satisfy the referencing concept then it should "OK".
This is possible. Yes..!!! This can be done. The only thing I did here is to make the two Objects as parent-child to achieve referencing. See demo below:
--Parent Object
CREATE OR REPLACE TYPE t_abonnement_type AS OBJECT
(
ref_abonnement_type NUMBER,
type_abonne VARCHAR(50),
MEMBER FUNCTION DISPLAY return varchar2
) NOT FINAL;
-- Member Funtion Body
CREATE OR REPLACE TYPE BODY t_abonnement_type
AS
MEMBER FUNCTION DISPLAY
return varchar2
IS
BEGIN
return ('Hi');
END DISPLAY;
END;
Testing my Parent Object:
SQL> SELECT t_abonnement_type(1,'a').display() col from DUAL;
COL
---
Hi
Child Object to achieve referencing concept
CREATE OR REPLACE TYPE t_abonnement
under t_abonnement_type
(
ref_abonnement NUMBER,
date_debut DATE,
MEMBER function V_DISPLAY return varchar2
);
--Member function
CREATE OR REPLACE TYPE BODY t_abonnement
AS
MEMBER Function V_DISPLAY return varchar2
IS
var varchar2(10);
BEGIN
var:= t_abonnement_type(1,'A').display(); --Calling Parent Member function here
return('Called from Child Object -->'||var);
END;
END;
Testing my Child Object to check if the parent Member function is referenced or not:
SQL> SELECT T_ABONNEMENT(1,'A',2,TO_DATE('30-JUN-2018','DD-MON-YYYY')).V_DISPLAY() COL FROM DUAL;
Col
---
Called from Child Object -->Hi
Note I haven't used overloading done in your code as I feel overloading makes the stuff harder to understand as an individual as well as for compiler.

Related

difference between creating a type with new keyword or without in plsql

In oracle pl/sql you can create an object with or without the new keyword.
Is there any difference how oracle threats these requests ?
So for example:
CREATE TYPE emp_object AS OBJECT(
emp_no NUMBER,
emp_name VARCHAR2(50),
salary NUMBER,
manager NUMBER,
CONSTRUCTOR FUNCTION emp_object(p_emp_no NUMBER, p_emp_name VARCHAR2,
p_salary NUMBER) RETURN SELF AS RESULT),
MEMBER PROCEDURE insert_records,
MEMBER PROCEDURE display_records);
/
CREATE OR REPLACE TYPE BODY emp_object AS
CONSTRUCTOR FUNCTION emp_object(p_emp_no NUMBER,p_emp_name VARCHAR2,
p_salary NUMBER)
RETURN SELF AS RESULT
IS
BEGIN
Dbms_output.put_line('Constructor fired..');
SELF.emp_no:=p_emp_no;|
SELF.emp_name:=p_emp_name;
SELF.salary:=p_salary;
SELF.managerial:=1001;
RETURN;
END:
MEMBER PROCEDURE insert_records
IS
BEGIN
INSERT INTO emp VALUES(emp_noemp_name,salary,manager);
END
MEMBER PROCEDURE display_records
IS
BEGIN
Dbms_output.put_line('Employee Name:'||emp_name);
Dbms_output.put_line('Employee Number:'||emp_no);
Dbms_output.put_line('Salary':'||salary);
Dbms_output.put_line('Manager:'||manager);
END:
END:
/
This is a type with spec and body, now you can create the object like this without the new keyword:
DECLARE
guru_emp_det emp_object;
BEGIN
guru_emp_det:=emp_object(1005,'RRR',20000,1000);
guru_emp_det.display_records;
guru_emp_det.insert_records;
COMMIT;
END;
But it is also possible with the keyword:
DECLARE
guru_emp_det emp_object;
BEGIN
guru_emp_det:= new emp_object(1005,'RRR',20000,1000);
guru_emp_det.display_records;
guru_emp_det.insert_records;
COMMIT;
END;
From the Type Constructor Expressions documentation:
Type Constructor Expressions
A type constructor expression specifies a call to a constructor method. The argument to the type constructor is any expression. Type constructors can be invoked anywhere functions are invoked.
type_constructor_expression::=
The NEW keyword applies to constructors for object types but not for collection types. It instructs Oracle to construct a new object by invoking an appropriate constructor. The use of the NEW keyword is optional, but it is good practice to specify it.
As to your question:
Is there any difference how oracle treats these requests?
No, there is no difference; the NEW keyword is optional.
Although the documentation states that the NEW keyword does not apply for collection types, in practice it does not appear to be invalid syntax and is both allowable and optional for collection types (there may be an edge-case I have not yet found where the NEW keyword is forbidden; however, on some brief tests I cannot find such a case).
fiddle

Object not supported in this context while Creating the package in Oracle

Hi I am trying to execute below statements for creating a package , but i am getting an error saying
Error(3,1): PLS-00540: object not supported in this context.
When trying to change it to RECORD i am getting another error
Error(3,32): PLS-00103: Encountered the symbol "RECORD" when expecting one of the following:
object opaque The symbol "object was inserted before "RECORD" to continue.
package Definition trying to execute
CREATE OR REPLACE PACKAGE "PKG_LOAN_LOGIC_SERVICE_V2" AS
TYPE LOAN_LOGIC_RESULT_TYPE AS OBJECT (
loanid NUMBER,
ret_value varchar2(500),
xPath varchar2(200)
);
TYPE LOAN_LOGIC_RESULTS_TABLE IS TABLE OF LOAN_LOGIC_RESULT_TYPE;
procedure PR_CORAL_LOAN_LOGIC(
in_loan_id IN wcts.loans.loan_id%TYPE,
in_trans_id IN wcts.loans.loan_id%TYPE,
as_errm out varchar2,
out_order_contents_tab out LOAN_LOGIC_RESULTS_TABLE
);
END PKG_LOAN_LOGIC_SERVICE_V2;
When i am trying to execute the user defined types in another standalone SQL Developer Window , its executing successfully .
CREATE OR REPLACE TYPE LOAN_LOGIC_RESULT_TYPE AS OBJECT (
loanid NUMBER,
ret_value varchar2(500),
xPath varchar2(200)
);
CREATE OR REPLACE TYPE LOAN_LOGIC_RESULTS_TABLE AS TABLE OF LOAN_LOGIC_RESULT_TYPE;
Why its not allowing me to run inside package ? or how i will create these types inside a package
Update:
create or replace procedure PR_CORAL_LOAN_LOGIC(
in_loan_id IN wcts.loans.loan_id%TYPE,
in_trans_id IN wcts.loans.loan_id%TYPE,
as_errm out varchar2,
out_order_contents_tab out LOAN_LOGIC_RESULTS_TABLE
)
is
begin
for o in (SELECT xpath_name FROM loan_logic WHERE attribute =
upper(TRIM('STATUS_0')))
loop
-- How i will get the user defined type here tp assign the values
--Assign the column values while iterating
END LOOP;
end PR_CORAL_LOAN_LOGIC;
According to Oracle documentation
You must define object types using the SQL statement CREATE TYPE
EDIT
For example
create or replace procedure PR_CORAL_LOAN_LOGIC(out_order_contents_tab out LOAN_LOGIC_RESULTS_TABLE)
is
obj LOAN_LOGIC_RESULT_TYPE;
begin
obj := LOAN_LOGIC_RESULT_TYPE(2, 'return value', 'some/path');
out_order_contents_tab := LOAN_LOGIC_RESULTS_TABLE();
out_order_contents_tab.extend;
out_order_contents_tab(1) := obj;
There are lots of examples available online, including Working with Collections. Not to mention the Oracle documentation.

Oracle, EXTENDS mus be declared

I'm trying to create object data types in Oracle.
I have an object type called type_transaction, I use this type of body
EXTENDS functions.
The compiler crashes the following error:
"identifier 'EXTENDS' must be declared.
I do not know what I'm doing wrong
This is type :
CREATE OR REPLACE TYPE type_transakcja AS OBJECT
(
id_transakcji NUMBER(10),
data_transakcji DATE,
pracownika_id REF type_pracownik,
klient_id REF type_klienta,
produkt_id REF type_produkt,
zamowienia k_zamowienie,
MAP MEMBER FUNCTION odwzoruj RETURN NUMBER,
MEMBER FUNCTION wartosc_zamowienia RETURN NUMBER,
MEMBER FUNCTION transakcja(produkty REF type_produkt, ile NUMBER)
RETURN NUMBER,
MEMBER PROCEDURE anuluj,
MEMBER PROCEDURE zatwierdz
);
CREATE TYPE k_zamowienie AS TABLE OF type_sprzedaz;
and this is body of type
CREATE OR REPLACE TYPE BODY type_transakcja IS
MEMBER FUNCTION transakcja(produkty REF type_produkt, ile NUMBER)
RETURN NUMBER IS
i INTEGER;
t k_zamowienie;
p type_produkt;
BEGIN
SELECT DEREF(produkty) INTO p FROM DUAL;
IF p.ilosc_magazynowa - ile >=0 THEN
p.ilosc_magazynowa:=p.ilosc_magazynowa-ile;
t:=SELF.zamowienia;
t:=extend(1);
i:= SELF.zamowienia.last();
t(i).ilosc:=ile;
t(i).cena:=SELF.wartosc_zamowienia();
t(i).produkt_id:=produkty;
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
END;
It's hard to be sure from the limited information you've provided, and what seems to be not quite the actual error you get; but it looks like you're just extending your collection incorrectly.
Assuming k_zamowienie is a table type, you're doing:
t:=extend(1);
instead of:
t.extend(1);
And you don't really need i, and if you do have it your index is going to be one off (as it's based on the size of the original table, not the cloned-and-extended on); you can do:
t(t.last).ilosc:=ile;
t(t.last).cena:=SELF.wartosc_zamowienia();
t(t.last).produkt_id:=produkty;
But even then you aren't doing anything with t, so this seems a bit pointless. Maybe you meant this?
zamowienia.extend(1);
zamowienia(zamowienia.last()).ilosc:=ile;
zamowienia(zamowienia.last()).cena:=SELF.wartosc_zamowienia();
zamowienia(zamowienia.last()).produkt_id:=produkty;

How to use self defined types with nested tables in PL/SQL member functions?

I am defining a MEMBER FUNCTION for this type:
CREATE OR REPLACE TYPE HITO_T (
nombre VARCHAR2 (20) ,
categoria VARCHAR2 (20) ,
estado VARCHAR2 (10) ,
costo_entrada NUMBER (10,0),
zonas ZONA_TABLE_T,
MEMBER FUNCTION listar_zonas RETURN ZONA_T
);
/
The type has an attribute for a nested table and the function must return all the values for that nested table, so what I have is:
CREATE OR REPLACE TYPE BODY HITO_T as
MEMBER FUNCTION listar_zonas RETURN VARCHAR2 is
BEGIN
return self.zonas
END listar_zonas;
END;
/
The definitions for ZONA_T and ZONA_TABLE_T are:
CREATE OR REPLACE TYPE ZONA_T UNDER LUGAR_TIPO (
nombre VARCHAR2(20),
tamano NUMBER,
poligonos POLIGONO_TABLE,
MEMBER FUNCTION listar_poligonos RETURN POLIGONO_T);
/
CREATE OR REPLACE TYPE ZONA_TABLE_T AS TABLE OF ZONA_T;
/
I can't seem to start trying stuff since I don't know how to call the function. My specific question is how to call the function to test it with actual objects on the database, instead of using one defined at the moment (that is, CALL HITO_T('a','b','c'...)... will not work because the function needs values from the zonas attribute, which is a nested table and it can't be defined at the moment just like that). Futhermore I am not sure I can just return «self.zonas» just like that.
Any ideas?
The VALUE statement was what I was looking for.

Possible to create Oracle Database object types inside of PL/SQL?

Is it possible to create an object type inside of a package in Oracle Database 10g? Something like:
create or replace package my_package as
type my_type as object (
id number(15)
);
end;
Gives:
Error(3,9): PLS-00540: object not supported in this context.
What I'm ultimately looking to be able to do is use polymorphism but also allow the objects to access tables and use PL/SQL, which isn't allowed in types defined outside of packages.
Thanks,
Jeff
From the Oracle 10g documentation:
Currently, you cannot define object
types in a PL/SQL block, subprogram,
or package.
So, unfortunately, no.
Update for Oracle 11g Release 2:
From Chapter 3 Using PL/SQL With Object Types of Oracle Database Object-Relational Developer's Guide:
Using object types in a PL/SQL block, subprogram, or package is a two-step process.
You must define object types using the SQL statement CREATE TYPE, in SQL*Plus or other similar programs.
After an object type is defined and installed in the schema, you can use it in any PL/SQL block, subprogram, or package.
In PL/SQL, you then declare a variable whose data type is the user-defined type or ADT that you just defined.
You can use PL/SQL in objects that are defined outside a PL/SQL package!! Use object bodies:
CREATE TYPE person_typ AS OBJECT (
idno NUMBER,
first_name VARCHAR2(20),
last_name VARCHAR2(25),
email VARCHAR2(25),
phone VARCHAR2(20),
MAP MEMBER FUNCTION get_idno RETURN NUMBER,
MEMBER PROCEDURE display_details ( SELF IN OUT NOCOPY person_typ ));
/
CREATE TYPE BODY person_typ AS
MAP MEMBER FUNCTION get_idno RETURN NUMBER IS
BEGIN
RETURN idno;
END;
MEMBER PROCEDURE display_details ( SELF IN OUT NOCOPY person_typ ) IS
BEGIN
-- use the PUT_LINE procedure of the DBMS_OUTPUT package to display details
DBMS_OUTPUT.PUT_LINE(TO_CHAR(idno) || ' ' || first_name || ' ' || last_name);
DBMS_OUTPUT.PUT_LINE(email || ' ' || phone);
END;
END;
/
copy-pasted this example from this link: http://www.mcs.csueastbay.edu/support/oracle/doc/10.2/appdev.102/b14260/adobjint.htm

Resources