In Oracle8, an object type combines attributes (data structures) and methods (functions and procedures) into a single programming construct. The object type construct allows programmers to defined their own reusable datatypes for use in PL/SQL programs and table and column definitions.
An instance of an object type is an object in the same way that variables are instances of scalar types. Objects are either persistent (stored in the database) or transient (stored only in PL/SQL variables). Objects can be stored in a database as a row in a table (a row object) or as a column in a table. A table of row objects can be created with syntax such as this:
CREATE TABLE table_name OF object_type;
When stored in the database as a row object, the object (row) has an OID (Object IDentifier) that is unique throughout the database.
An object type has two parts: the specification and the body. The specification is required and contains the attributes and method specifications. The syntax for creating the object type specification is:
CREATE [OR REPLACE] TYPE obj_type_name [AUTHID CURRENT_USER | DEFINER] -- Oracle8i AS OBJECT ( attribute_name datatype,..., [MEMBER | STATIC PROCEDURE | FUNCTION program_spec], [ORDER | MAP MEMBER FUNCTION comparison_function_spec], [PRAGMA RESTRICT_REFERENCES(program_name, purities)] );
All attribute specifications must appear before all method specifications. Object attributes, like variables, are declared with a name and a datatype. The name can be any legal identifier. Attribute datatypes can be any SQL datatype except LONG, LONG RAW, NCHAR, NVARCHAR2, NCLOB, ROWID, and UROWID. Attributes cannot have datatypes unique to PL/SQL such as BOOLEAN.
Member function and procedure headers are listed in the object type specification in a comma-delimited list. Unlike in a package specification, commas (not semicolons) terminate the object type program specifications. To support object comparisons and sorting, the type can optionally include one comparison method -- either ORDER or MAP.
Member programs can assert purity with the RESTRICT_REFERENCES pragma. (See the earlier Section 1.15.1, "Syntax for Calling Stored Functions in SQL " section for more information on this pragma.) Member methods can be overloaded in object types following the same rules as function and procedure overloading in packages.
The syntax for creating the object type body is:
CREATE [OR REPLACE] TYPE BODY obj_type_name AS OBJECT ( [MEMBER | STATIC PROCEDURE | FUNCTION program_body;] [ORDER | MAP MEMBER FUNCTION comparison_function_body;] );
The keyword STATIC is new starting with Oracle8 i. Static methods do not use the current SELF object.
Every object has a default method, a constructor , which has the same name as the object type. The constructor constructs an instance of the object type from the elements passed to it, and returns the new object. This built-in method:
Has the same name as the object type
Is a function that returns an object of that type
Accepts attributes in named or positional notation
Must be called with a value (or NULL) for every attribute -- there is no DEFAULT clause for object attributes
Cannot be modified
If you wish to create your own pseudo-constructor, create a STATIC function that returns an object of the corresponding type.
All non-static methods have the built-in parameter SELF, which references the instance of the object. The default mode for the SELF parameter is IN for functions and IN OUT for procedures. SELF can be explicitly declared with a non-default mode.
ORDER and MAP methods establish ordinal positions of objects for non-equality comparisons such as "<" or "between" and for sorting (ORDER BY, GROUP BY, DISTINCT). An ORDER function accepts two parameters: SELF, and another object of the same type. It must return an INTEGER with values of -1, 0, 1, or NULL.
See the following table for a description of these return values.
Return Value |
Object Comparison |
---|---|
-1 |
SELF < second object |
0 |
SELF = second object |
1 |
SELF > second object |
NULL |
Undefined comparison, i.e., attributes needed for the comparison are NULL |
For example, the Senate ranks majority party members higher than non-majority party members and within the majority (or non-majority), by years of service. Here is an example ORDER function incorporating these rules:
CREATE TYPE senator_t AS OBJECT ( majority boolean_t, yrs_service NUMBER, ORDER MEMBER FUNCTION ranking (other IN senator_t) RETURN INTEGER ); CREATE OR REPLACE TYPE BODY senator_t AS ORDER MEMBER FUNCTION ranking (other IN senator_t) RETURN INTEGER IS BEGIN IF SELF.majority.istrue() AND other.majority.istrue() THEN RETURN SIGN(SELF.yrs_service - other.yrs_service); ELSIF SELF.majority.istrue() AND other.majority.isfalse() THEN RETURN 1; ELSIF SELF.majority.isfalse() AND other.majority.istrue() THEN RETURN -1; ELSIF SELF.majority.isfalse() AND other.majority.isfalse() THEN RETURN SIGN(SELF.yrs_service - other.yrs_service); END IF; END ranking; END;
A MAP function accepts no parameters and returns a scalar datatype such as DATE, NUMBER, or VARCHAR2 for which Oracle already knows a collating sequence. The MAP function translates, or maps , each object into a scalar datatype space that Oracle knows how to compare. When they exist, MAP methods are often more efficient than ORDER methods and are required for hash joins on the object in SQL.
If no ORDER or MAP function exists for an object type, SQL, but not PL/SQL, supports only limited equality comparisons of objects. Objects are equal if they are of the same object type and if each attribute is equal.
There are three ways to initialize an object:
Using the constructor method
Directly assignmening an existing object to a new object
Using SELECT INTO or FETCH INTO
Here is an example using each initialization technique:
DECLARE project_boiler_plate project_t; build_web_site project_t; -- Initialize via constructor. new_web_mgr proj_mgr_t := proj_mgr_t('Ruth', 'Home Office'); CURSOR template_cur IS SELECT VALUE(proj) FROM projects WHERE project_type = 'TEMPLATE' AND sub_type = 'WEB SITE'; BEGIN OPEN template_cur; -- Initialize via FETCH INTO. FETCH template_cur INTO project_boiler_plate; -- Initialize via assignment. build_web_site := project_boiler_plate; ...
After an object is initialized, it can be stored in the database, and you can then locate and use that object with the REF, VALUE, and DEREF operators.
REF, short for REFerence, designates a datatype modifier or an operator to retrieve a logical pointer to an object. This pointer encapsulates the OID and can simplify navigation among related database objects.
The syntax for a REF operator is:
REF(table_alias_name)
For example:
SELECT REF(p) FROM pets p WHERE ...
A PL/SQL variable can hold a reference to a particular object type:
DECLARE petref REF Pet_t; BEGIN SELECT REF(p) INTO petref FROM pets p WHERE ...
Through deletions, REFs can reference a nonexistent object -- called a dangling REF -- resulting in a state that can be detected with the IS DANGLING predicate. For example:
UPDATE pets SET owner_ref = NULL WHERE owner_ref IS DANGLING.
Use the VALUE operator to retrieve a row object as a single object rather than multiple columns. The syntax for the VALUE operator is:
VALUE(table_alias_name)
For example:
SELECT VALUE(p) FROM pets p WHERE ...
Use the DEREF operator to retrieve the value of an object for which you have a REF. The syntax for the DEREF operator is:
DEREF(table_alias_name)
For example:
DECLARE person_ref REF person_t; author person_t; BEGIN -- Get the ref. SELECT REF(p) INTO person_ref FROM persons WHERE p.last_name ='Pribyl'; -- Dereference the pointer back to the value. SELECT DEREF(person_ref) INTO author FROM dual; ...
Additionally, Oracle uses an OID internally as a unique key to each object. Like a ROWID, you don't typically use an OID directly.
The following table shows ways of referencing persistent objects.
Scheme |
Description |
Applications |
---|---|---|
OID |
An opaque, globally unique handle, produced when the object is stored in the database as a table (row) object. |
This is the persistent object's handle; it's what REFs point to. Your program never uses it directly. |
VALUE |
An operator. In SQL, it acts on an object in an object table and returns the object's contents . Different from the VALUES keyword found in some INSERT statements. |
Allows quasi-normalizing of object-relational databases and joining of object tables using dot navigation. In PL/SQL, REFs serve as input/output variables. |
REF |
A pointer to an object. May be used within a SQL statement as an operator or in a declaration as a type modifier. |
Used when fetching a table (row) object into a variable, or when you need to refer to an object table as an object instead of a list of columns. |
DEREF |
Reverse pointer lookup for REFs. |
Used for retrieving the contents of an object when all you know is its REF. |
You can add methods, but not attributes, to an object type stored in the database using the ALTER TYPE statement:
ALTER TYPE type_name REPLACE AS OBJECT ( new_object_type_specification );
The only supported change you can make in the new object type specification is to include new methods.
It is also possible to rebuild an object table with different physical storage characteristics by using the built-in procedure DBMS_DDL.ALTER_TABLE_REFERENCEABLE.
The syntax for dropping an object type is:
DROP TYPE type_name [FORCE];
You can drop only an object type that has not been implemented in a table (or you can drop the tables first). The FORCE option will drop object types even if they have dependencies, but FORCE will irreversibly invalidate any dependent objects such as tables. FORCE does not do a DROP CASCADE.
Copyright (c) 2000 O'Reilly & Associates. All rights reserved.