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

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

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.

How can i use REF type in PL/SQL 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.

Create or replace global subtype

I know that I can create a subtype inside a package specification like:
CREATE OR REPLACE PACKAGE XY
AS
SUBTYPE type_sdebug IS VARCHAR (200);
...
END;
/
If I want to use the same subtype within another package then I need to redefine the same type again. Is there a way to create or replace a global subtype such as:
CREATE OR REPLACE TYPE STRING_ARRAY AS VARRAY(500) OF VARCHAR2(30);
/
As far as I know, SUBTYPEs are a PL/SQL feature, so you cannot create them globally. But nothing prevents you from using a type defined in your package XY in another package (e.g. AB):
CREATE OR REPLACE PACKAGE XY
AS
SUBTYPE type_sdebug IS VARCHAR (200);
END;
CREATE OR REPLACE PACKAGE AB
AS
PROCEDURE print_it(p_Debug in XY.type_sdebug);
END;
CREATE OR REPLACE PACKAGE BODY AB
AS
PROCEDURE print_it(p_Debug in XY.type_sdebug) is
begin
dbms_output.put_line(p_Debug);
end;
END;
declare
v_Debug XY.type_sdebug default 'hello world';
begin
ab.print_it(v_Debug);
end;
Now that I've read the question correctly *{;-) , according to the documentation you can indeed create a subtype:
"This statement shows how the subtype corporate_customer_typ in the sample oe schema was created. It is based on the customer_typ supertype created in the preceding example and adds the account_mgr_id attribute. A hypothetical name is given to the table so that you can duplicate this example in your test database:"
CREATE TYPE corporate_customer_typ_demo UNDER customer_typ
( account_mgr_id NUMBER(6)
);
You may need additional privileges to be able to do so though, according to the prerequisites for creating types:
"To create a subtype, you must have the UNDER ANY TYPE system privilege or the UNDER object privilege on the supertype."

Passing values from Oracle Object type parameter to PLSQL Table type parameter

How can we pass a parameter that is declared as an Oracle Object type to a Procedure having a parameter as PLSQL Table type?
Eg:
Procedure A(p_obj_emp t_obj_emp)
Procedure B(p_emp_tab t_emp_tab)
Where t_obj_emp = Oracle Object and t_emp_tab is a PLSQL Table of binary_integer
How can we pass a parameter that is declared as an Oracle Object type to a Procedure having a parameter as PLSQL Record type?
Eg:
Procedure C(p_obj_dept t_obj_dept)
Procedure D(p_dept_rec t_dept_rec)
Where t_obj_dept = Oracle Object having 2 fields (deptid, deptname) and t_dept_rec is declared in package specification as t_dept_rec with 2 fields (deptid, deptname).
Kindly help with some example.
Thanks in advance
The following compiles for me and appears to do what you want:
CREATE OR REPLACE TYPE t_obj_emp AS OBJECT (
emp_id INTEGER,
emp_name VARCHAR2(100)
);
/
CREATE OR REPLACE TYPE t_obj_dept AS OBJECT (
dept_id INTEGER,
dept_name VARCHAR2(100)
);
/
CREATE OR REPLACE PACKAGE my_pkg AS
TYPE t_emp_tab IS TABLE OF t_obj_emp INDEX BY BINARY_INTEGER;
TYPE t_dept_rec IS RECORD (
dept_id INTEGER,
dept_name VARCHAR2(100)
);
PROCEDURE A(p_obj_emp t_obj_emp);
PROCEDURE B(p_emp_tab t_emp_tab);
PROCEDURE C(p_obj_dept t_obj_dept);
PROCEDURE D(p_dept_rec t_dept_rec);
END;
/
CREATE OR REPLACE PACKAGE BODY my_pkg AS
PROCEDURE A(p_obj_emp t_obj_emp)
IS
v_emp_tab t_emp_tab;
BEGIN
v_emp_tab(1) := p_obj_emp;
B(v_emp_tab);
END;
PROCEDURE B(p_emp_tab t_emp_tab) IS BEGIN NULL; END;
PROCEDURE C(p_obj_dept t_obj_dept)
IS
v_dept_rec t_dept_rec;
BEGIN
v_dept_rec.dept_id := p_obj_dept.dept_id;
v_dept_rec.dept_name := p_obj_dept.dept_name;
D(v_dept_rec);
END;
PROCEDURE D(p_dept_rec t_dept_rec) IS BEGIN NULL; END;
END;
/
Note that there isn't any 'convenient' way to create one object/record from another, even if they have identical members (such a t_obj_dept and t_dept_rec in the example above). You must copy across the values of all the fields individually.
You say that t_emp_tab is a "PLSQL Table of binary_integer". I'm guessing you mean that it's a PL/SQL Table of some type indexed by binary_integer, as it's far more common to index these tables by binary_integer than it is to store binary_integers in them. For the example above I've assumed that it's a table of t_obj_emps. If it's not, you'll have to map the t_obj_emp object to whatever type of object or record t_emp_tab is a table of.

Resources