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

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.

Related

PL/SQL inheritance implementation where procedure is implemented under the sub object

Entity Relationship Diagram
The problem is
Given the inheritance hierarchy depicted in the vehicles object model find solution for the following questions
1. Identify the appropriate object types and implement the vehicle inheritance type hierarchy
2. The get_vehicle member function returns the complete information of the appropriate vehicles type
3. set_gear_count member procedure takes two parameters the gear_count and the vehicle id and updates a bicycle gear_count.
4. Create anonymous PLSQL block and instantiate truck and bicycle instances and insert them in the appropriate table. Then demonstrate the use of get_vechile and set_gear_count member methods.
For this problem I wrote the following PL/SQL but I am getting the following error
SQL> #inheritance;
Warning: Type Body created with compilation errors.
The error occurs when I try to run the CREATE TYPE BODY bicycle AS body and the specific area of the error is set_gear_count procedure.
SQL> show error
Errors for TYPE BODY BICYCLE:
LINE/COL ERROR
-------- -----------------------------------------------------------------
10/1 PL/SQL: SQL Statement ignored
10/13 PL/SQL: ORA-00947: not enough values
SQL>
The code I wrote is the following
--creating the base vehicle object type
CREATE OR REPLACE TYPE vehicle_t AS OBJECT
(
vehicle_id NUMBER,
manufacturer VARCHAR2(30),
purchase_date DATE,
color VARCHAR2 (10),
MEMBER FUNCTION get_vehicle RETURN VARCHAR2
)NOT FINAL;
/
CREATE TYPE BODY vehicle_t AS
MEMBER FUNCTION get_vehicle RETURN VARCHAR2
IS
BEGIN
RETURN 'Vehicle ID:'|| TO_CHAR (vehicle_id) || 'Manufacturer:'|| manufacturer || 'Purchase Date:'||purchase_date||'Color:'||color;
END get_vehicle;
END;
/
-- CREATING SUB TYPE OF VEHICLE_T POWERED_VEHICLE
CREATE OR REPLACE TYPE powred_vehicle UNDER vehicle_t
(
fule_type VARCHAR2(30),
license_number VARCHAR2 (10),
model VARCHAR2 (10),
OVERRIDING MEMBER FUNCTION get_vehicle RETURN VARCHAR2
)FINAL;
/
CREATE TYPE BODY powred_vehicle AS
OVERRIDING MEMBER FUNCTION get_vehicle RETURN VARCHAR2
IS
BEGIN
RETURN (self AS vehicle_t).get_vehicle || 'Fuel Type:'|| fule_type || 'License Number:'||license_number||'Model:'||model;
END get_vehicle;
END;
/
CREATE OR REPLACE TYPE bicycle UNDER vehicle_t
(
gear_count number,
OVERRIDING MEMBER FUNCTION get_vehicle RETURN VARCHAR2,
MEMBER PROCEDURE set_gear_count (p_gear_count IN bicycle, p_vehicleid IN vehicle_t)
)FINAL;
/
CREATE TABLE vehicle_tab OF bicycle;
This is where the error occurs.
CREATE TYPE BODY bicycle AS
OVERRIDING MEMBER FUNCTION get_vehicle RETURN VARCHAR2
IS
BEGIN
RETURN (self AS vehicle_t).get_vehicle || 'Gear Count:'|| TO_CHAR(gear_count);
END get_vehicle;
MEMBER PROCEDURE set_gear_count (p_gear_count IN bicycle, p_vehicleid IN vehicle_t)
IS
BEGIN
INSERT INTO vehicle_tab VALUES (p_gear_count, p_vehicleid);
END set_gear_count;
END;
/
I seems vehicle_tab is a table of bicycle. I think you want to do this?
INSERT INTO vehicle_tab VALUES (SELF);
Also, I think it is confusing that p_gear_count is of type bicycle: shouldn't it be a number of some kind?

Is there a way to allow an object function to return a variable without passing in that variable in the constructor?

I'm working on a project that requires me to create many different subtypes under one supertype. This supertype is supposed to have a function that gets a name, but the name will only come from the subtype. Is there a way to create the type and allow it to have a function that returns a value from a subtype?
I have tried just removing the function altogether, but in order to complete this project, I need it to have this function, because the function is used through this type to get the information from the objects that I insert into a table.
CREATE OR REPLACE
TYPE test_obj IS OBJECT
( OBJ_ID NUMBER
, OBJ_NAME VARCHAR2(30)
, CONSTRUCTOR FUNCTION test_obj
( OBJ_ID NUMBER
, OBJ_NAME VARCHAR2)
RETURN SELF AS RESULT
, MEMBER FUNCTION GET_OBJ_NAME RETURN VARCHAR2
, MEMBER PROCEDURE SET_OBJ_NAME
( ONAME VARCHAR2)
, MEMBER FUNCTION GET_NAME RETURN VARCHAR2
, MEMBER FUNCTION TO_STRING RETURN VARCHAR2)
INSTANTIABLE NOT FINAL;
/
CREATE OR REPLACE
TYPE BODY test_obj IS
CONSTRUCTOR FUNCTION test_obj
( OBJ_ID NUMBER
, OBJ_NAME VARCHAR2 )
RETURN SELF AS RESULT IS
BEGIN
self.OBJ_ID := OBJ_ID;
self.OBJ_NAME := OBJ_NAME;
RETURN;
END test_obj;
MEMBER FUNCTION GET_OBJ_NAME
RETURN VARCHAR2 IS
BEGIN
RETURN OBJ_NAME;
END GET_OBJ_NAME;
MEMBER PROCEDURE SET_OBJ_NAME
(OBJ_NAME VARCHAR2) IS
BEGIN
self.OBJ_NAME := OBJ_NAME;
END SET_OBJ_NAME;
-- This is the function that I need to fix
MEMBER FUNCTION GET_NAME
RETURN VARCHAR2 IS
NAME VARCHAR2(30)
BEGIN
RETURN NAME;
END GET_NAME;
MEMBER FUNCTION TO_STRING
RETURN VARCHAR2 IS
BEGIN
RETURN '['||self.OBJ_ID||']['||self.OBJ_NAME||']';
END TO_STRING;
END;
/
I want to be able to override the GET_NAME function in subclasses, but I don't want to pass in a NAME variable, because this type won't ever receive a NAME variable, the subtypes are the only ones that will receive it. I won't be able to instantiate it properly if I have the name passed in through the constructor.
Any help would be much appreciated. Thank you.

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.

How can I delete a member function created in oracle

How can I delete a member function created inside oracle type object without dropping the entire type?
I never used it but according documentation you might be able to use
alter type {type_name} DROP MEMBER {function_spec} CASCADE;
Note, {function_spec} is the function name plus RETURN clause, e.g.
ALTER TYPE ttest DROP MEMBER FUNCTION f_name_2 RETURN VARCHAR2 CASCADE;
Afterwards you have to re-create the TYPE BODY without the dropped function, i.e. CREATE OR REPLACE TYPE BODY ...
As far as I can tell, you can't (unless you call CREATE OR REPLACE to be not dropping).
P.S. What's even worse, if there are dependent types that use the type with a member function you'd want to drop, you'll need to drop everything cascade. Which means that - as a function doesn't have to eat or drink - leave it alone.
[EDIT; after seeing Wernfried's answer]
It seems that I was wrong. Apparently, it really works. Syntax is somewhat strange (it requires to specify the RETURN clause (?!?)), but hey - that's what Oracle says. So, today I learnt something new.
An example:
SQL> create or replace type ttest is object
2 (some_name varchar2(20),
3 member function f_name return varchar2
4 );
5 /
Type created.
SQL> create or replace type body ttest as
2 member function f_name
3 return varchar2
4 is
5 begin
6 return self.some_name;
7 end f_name;
8 end;
9 /
Type body created.
SQL> alter type ttest drop member function f_name return varchar2;
Type altered.
SQL> desc ttest
Name Null? Type
----------------------------------------- -------- ----------------------------
SOME_NAME VARCHAR2(20)
SQL>

Return a User Defined Table From a Query Plus Hardcoded Variable in PL/SQL

I have the following scenario:
I need to feed into either a Procedure or Function the Following Parameters:
Link_1_ID, Link_2_ID, Address1, Address2, City, State, Zip, Address_Type
These will be used to query a table (we'll call the Table ADDRESS_INFO) surrounding some logic and then hardcode the variable LOC_CDE with '0001'.
I then need this all to return in the form of a User Defined Table type (though it should only pull one record at a time).The table would output the following:
Link_1_ID, Link_2_ID, Address1, Address2, City, State, Zip, LOC_CDE (no Address_Type)
I am VERY new to PL/SQL and have had little luck in returning anything. I would also prefer to keep ALL code in one defined PACKAGE (which is also causing trouble).
Any advice or help would be appreciated.
You want your own UDT, saying that your function will only return one value; so I believe you may first need to define your type, for example:
create or replace type yourType as object (fieldA number, fieldB varchar2(20), fieldC varchar2(20));
Then you can define your function with all the parameters you need, returning a single instance of your UDT:
create or replace function yourFunction (parA number, parB varchar2) return yourType is
returnVal yourType;
begin
select yourType(parA, parB || ' something', 'FIXED_VALUE')
into returnVal
from dual;
return returnVal;
end;
This is only one way to handle your UDT variables; for example you could fill the fields of you UDT explicitly:
create or replace function yourFunction (parA number, parB varchar2) return yourType is
returnVal yourType;
begin
returnVal := new yourType(null, null, null); /* you need an initialization here */
select parA, parB || ' something', 'FIXED_VALUE'
into returnVal.fieldA, returnVal.fieldB, returnVal.fieldC
from dual;
return returnVal;
end;
You could use some other variables to fetch into and then use these variables to fill your return value, or define a constructor to handle the creation of your UDT instances with some custom logic, and so on... this is just a very basic example of simple ways to handle a UDT and use it as a return value of a function.

Resources