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?
Related
I have such objects and methods:
create or replace type PolicyType as object(
policy_id number,
policy_nr varchar2(20),
price number) NOT FINAL;
/
create or replace type TravelerType as object(
first_name varchar2(30),
last_name varchar2(30),
pers_code varchar2(12));
/
create or replace type TravelersType as table of TravelerType;
/
create or replace type ref_TargetPlaceType as object (
target_code varchar2(4),
description varchar2(30));
/
create or replace type TravelPolicyType under PolicyType (
target_code REF ref_TargetPlaceType,
traveler_data TravelersType,
MEMBER FUNCTION getTraveler (p_code IN varchar2) RETURN TravelerType,
MEMBER PROCEDURE addTraveler( traveler IN TravelerType ));
/
CREATE OR REPLACE TYPE BODY TravelPolicyType AS
MEMBER FUNCTION getTraveler(p_code IN varchar2) RETURN TravelerType AS
BEGIN
for i in 1 .. self.traveler_data.count() loop
if( self.traveler_data(i).pers_code = p_code )
then
return self.traveler_data(i);
end if;
end loop;
END;
MEMBER PROCEDURE addTraveler(traveler IN TravelerType) AS
BEGIN
self.traveler_data.extend();
self.traveler_data(self.traveler_data.count) :=traveler;
END;
END;
I am tying to call methods, bet getting error for both
ORA-04063: type body "SQL_LPZCXWDSKRAXJUEWPMXNUMWYH.TRAVELPOLICYTYPE" has errors ORA-06512:
declare
policy_d TravelPolicyType;
traveler TravelerType;
begin
select value(a) into policy_d from travel_policies a where a.policy_nr='TP00000000003';
traveler:=policy_d.getTraveler('050976-12568');
end;
declare
policy_d TravelPolicyType;
new_traveler TravelerType;
begin
select value(a) into policy_d from travel_policies a where a.policy_nr='TP00000000003';
new_traveler:=TravelerType('Test','Traveler', '123456-44444');
policy_d.addTraveler(new_traveler);
end;
Can not understand what I am doing wrongly. Please help with advise
See what errors are reported in that object:
select * from user_errors;
NAME
TYPE
SEQUENCE
LINE
POSITION
TEXT
ATTRIBUTE
MESSAGE_NUMBER
TRAVELPOLICYTYPE
TYPE BODY
1
4
22
PLS-00302: component 'TRAVELERS_DATA' must be declared
ERROR
302
TRAVELPOLICYTYPE
TYPE BODY
2
4
3
PL/SQL: Statement ignored
ERROR
0
Your type has traveler_data, but the body refers to travelers_data. You need to make that naming consistent.
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.
I'm still new to this and trying to get my head around it. UDT are able to define methods which you can call on the object stored, I seem to create a method that returns a value fine but was wondering if it's possible create a setter methods. This scenario isn't really useful but it's simple just for clarification
For example, I have this type:
create TYPE TestType2 AS OBJECT(
Numb NUMBER(4),
Str VARCHAR2(10),
MEMBER FUNCTION setNum(numba NUMBER) RETURN NUMBER
);
Which compiles fine so my assumption setter methods are allow
I've tried create the body type below:
CREATE TYPE BODY TestType2 as
member function setNum(numba NUMBER) return NUMBER is
begin
SELF.Numb := numba;
return SELF.Numb;
END;
END;
However this won't work giving me the errors below:
Error(3,9): PL/SQL: Statement ignored
Error(3,14): PLS-00363: expression 'SELF.NUMB' cannot be used as an assignment target
Is there a way to create a set method or is this only allowed in store procedures?
This is an obscure error. The problem is member functions take an implicit parameter of SELF. So if you want to change something you need to make the parameter explicit:
create or replace TYPE TestType2 AS OBJECT(
Numb NUMBER(4,0),
Str VARCHAR2(10),
MEMBER procedure setNum(self in out TestType2, numba NUMBER )
);
/
CREATE or replace TYPE BODY TestType2 as
member function setNum(self in out TestType2 , numba NUMBER) return NUMBER
is
begin
self.Numb := numba;
return SELF.Numb;
END;
END;
/
Note that the SELF parameter remains implicit when calling the function:
declare
t TestType2 := TestType2(4, 'TEST');
n pls_integer;
begin
dbms_output.put_line('1' || t.numb);
n := t.setNum(8);
dbms_output.put_line('2' || t.numb);
end;
/
Incidentally, setter methods don't need to be functions; we can have member procedures too.
create or replace TYPE TestType2 AS OBJECT(
Numb NUMBER(4,0),
Str VARCHAR2(10),
MEMBER procedure setNum(self in out TestType2, numba NUMBER ),
MEMBER FUNCTION getNum RETURN NUMBER
);
/
CREATE or replace TYPE BODY TestType2 as
member procedure setNum(self in out TestType2, numba NUMBER )
is
begin
self.Numb := numba;
END;
MEMBER FUNCTION getNum RETURN NUMBER
is
begin
return self.numb;
end;
END;
/
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.
I am trying to print an table type for debugging purposes, but don't know how. I tried the following two methods, neither of which work:
dbms_output.put_line (V_TEMP_TABTYPE(1));
dbms_output.put_line (V_TEMP_TABTYPE);
The error generated is: PLS-00306: wrong number or types of arguments in call to.
So, how can I print the contents of a table type? Or is there a different way to display the contents?
The table_type and the type it references are::
create or replace TYPE MY_TYPE IS OBJECT( MyString Varchar(20)
, counter Number(9) );
create or replace TYPE MY_TABTYPE AS TABLE OF MY_TYPE;
Oracle has objects but it's ... different. Not exactly sure with your question if you want to see the values of the properties or if you want to actually see the type.
CREATE OR REPLACE TYPE MY_TYPE IS OBJECT (
MyString Varchar(20)
, counter Number(9)
);
Now run some code for it.
DECLARE
myType MY_TYPE;
BEGIN
myType := MY_TYPE('ABC123',0);
-- To see the values reference the properties
DBMS_OUTPUT.PUT_LINE(myType.mystring);
-- To see they TYPE of the OBJECT
DBMS_OUTPUT.PUT_LINE(SYS.ANYDATA.CONVERTOBJECT(myType).getTypeName());
END;
Of course you can create methods on the object to return information for you a bit easier.
CREATE OR REPLACE TYPE MY_TYPE IS OBJECT (
MyString Varchar(20)
, counter Number(9)
, MEMBER FUNCTION getType RETURN VARCHAR2
, MEMBER FUNCTION toString RETURN VARCHAR2
)
/
CREATE OR REPLACE TYPE BODY MY_TYPE
AS
MEMBER FUNCTION getTYPE RETURN VARCHAR2 IS
BEGIN
RETURN SYS.ANYDATA.CONVERTOBJECT(SELF).getTypeName();
END;
MEMBER FUNCTION toString RETURN VARCHAR2 IS
BEGIN
RETURN 'MY_TYPE('||self.mystring||','||self.counter||')';
END;
END;
/
You can call the functions on the object now makes it easier to read imo.
DECLARE
mytype MY_TYPE;
BEGIN
mytype := MY_TYPE('AGAIN','0');
DBMS_OUTPUT.PUT_LINE(mytype.toString);
DBMS_OUTPUT.PUT_LINE(mytype.getType);
END;
dbms_output.put_line(v_temp_tabtype(i).myString);