Table of Contents
This chapter describes the object types provided by Tibero and explains their usage.
Object types are user-defined types. They are used for expressing object that exist in the real-world such as customer orders and customers. New object types can be defined by using existing types such as NUMBER, and VARCHAR, as well as previously defined object types or collection types. As well, users can specify an object type as a column time when creating a table, or can create a table to store only object type values. These tables are called object tables.
In Tibero, objects are created as an extension of the relational model. To do this, the SQL syntax and PSM have been extended.
An object type is a type of data type. Therefore, an object type can be used in most cases where a data type can be specified. An object type can be used for specifying a column type when creating a table, or can be used for speciying a variable type when defining PSM. To define a type, use the CREATE TYPE statement. If a type's method exists, then use the CREATE TYPE BODY statement.
The following is an example of defining a customer type.
[Example 6.1] Object Type
CREATE TYPE customer_type AS OBJECT ( custno NUMBER, name VARCHAR2(40), phone VARCHAR2(20), MEMBER FUNCTION tostring RETURN VARCHAR); / CREATE TYPE BODY customer_type AS MEMBER FUNCTION tostring RETURN VARCHAR IS BEGIN RETURN custno || ':' || name || ':' || phone; END; END; /
The following two items are needed for configuring an object type.
Constraints cannot be placed on the properties of the CREATE TYPE statement. However, when using a type in a CREATE TABLE statement, then constrains can be placed on the properties value.
There are objects that can contain data via object types, and they are called object type values or simply objects. Depending on the type of data in an object, multiple objects can exist in an object that can be created by a single object type. The following is an example of specifying a column type as object type when creating a table, and storing the actual object (object type value) in the table.
[Example 6.2] Object Type Value
CREATE TABLE customer ( cust_obj customer_type, status VARCHAR(1)); INSERT INTO customer VALUES (customer_type(1, 'James', '111-222-3333'), 'V');
In the above example, an object type called customer_type whose name is 'James' is stored in the customer table. The customer_type(...) expression is the default constructor. It is a syntax that can be used for constructing an object of this object type.
The type used for storing an object in a table is determined when creating a table. There are two types.
Table column type
Typically, a column type is specified in the CREATE TABLE syntax. However, if an object type is specified instead, then an object is stored in the table column type. This type of object is called a column object.
Object table type
Users can create a table that can store objects of only one object type. This is called an object table. Objects created here are called row objects.
The following is an example of a CREATE TABLE statement, which creates object tables.
When the user creates an object table, columns corresponding to the properties of the object type are created in the corresponding table columns. Therefore, the customer_type_tab table in the above example is viewed as a table with 3 columns.
[Example 6.4] Viewing an Object Table (1)
SQL> desc customer_type_tab; COLUMN_NAME TYPE CONSTRAINT ---------------------------------------- ------------------ -------------------- CUSTNO NUMBER NAME VARCHAR(40) PHONE VARCHAR(20)
An object table stores objects, and users can import objects from the table by using the VALUE(x) expression.
You can access the object stored in the object table by giving the object table alias (x) as an argument to the expression as follows
[Example 6.5] Viewing an Object Table (2)
INSERT INTO customer_type_tab VALUES(customer_type(1, 'James', '111-222-3333')); INSERT INTO customer_type_tab VALUES(2, 'Bob', '444-555-6666'); DECLARE c1 customer_type; BEGIN SELECT VALUE(x) into c1 FROM customer_type_tab x where custno = 1; dbms_output.put_line(c1.tostring()); END; /
As shown in the above example, when performing an INSERT on an object table, only one object expression (in the above, a default constructor was used) needs to be specified. As well, INSERT can also be performed by specifying each individual property values.
A collection type is used for collecting the same type of data and combining them into a single value. In Tibero, users define a collection type, just like an object type. Two types of collection types are provided in Tibero: variable array and nested table. A collection type can also be specified as a property type when users create a new object type. For more information, refer to “Chapter 7. Collection Type”.
The following is an example of a CREATE TYPE syntax, which defines a nested table and defines an object type which contain the properties of an object type.
CREATE TYPE customer_ntab_type AS TABLE OF customer_type; / CREATE TYPE int_group_type AS OBJECT ( group_no NUMBER, members customer_ntab_type); /
This section describes the various components that make up an object in Tibero.
This section describes the components of objects used in SQL.
If the value of an object itself is NULL, it is called a NULL object. A NULL object is different than an object whose properties' values are all NULL (these objects are not NULL objects). These objects, whose properties' values are all NULL, can have NULL values for specific properties, and this properties value can be changed to a non-NULL value by using a procedure or function. However, a NULL object cannot change its properties' values, as well as cannot invoke its method.
The following is an example of inserting a non-NULL object which contains both NULL objects and NULL properties' values in the object column of a table that contains column objects.
[Example 6.6] NULL Objects and Objects' NULL Properties
CREATE TYPE customer_type2 AS OBJECT ( custno NUMBER, name VARCHAR2(40), phone VARCHAR2(20), MEMBER FUNCTION tostring RETURN VARCHAR DETERMINISTIC); / CREATE TYPE BODY customer_type2 AS MEMBER FUNCTION tostring RETURN VARCHAR DETERMINISTIC IS BEGIN RETURN custno || ':' || name || ':' || phone; END; END; / CREATE TABLE customer2 ( cust_obj customer_type2, status VARCHAR(1)); INSERT INTO customer2 VALUES (Null, 'I'); INSERT INTO customer2 VALUES (customer_type2 (NULL, NULL, NULL), 'V');
An object table's row objects cannot be NULL objects. Empty collections, which do not contain any components, are not NULL collections.
Just like users can define constraints on a table, they can also define constraints on a table that uses object types. However, constraints can only be defined for properties that exist at the bottom of object type's containment tree. The properties at the very bottom cannot be object type properties, so these properties have built-in types.
The following is an example of specifying an object type's property as the primary key of an object table when creating an object table.
[Example 6.7] Specifying an Object Table as the Primary Key when Creating an Object Table
CREATE TABLE customer_type_tab2 of customer_type2 ( custno PRIMARY KEY);
When a table contains an object column, a constraint can also be defined in the object's properties. In this case, it can be defined with a period (.).
[Example 6.8] Setting a Constraint on an Object Column
CREATE TABLE customer3 ( cust_obj customer_type2, status VARCHAR(1), CONSTRAINT cust_check_cons CHECK (cust_obj.custno IS NOT NULL));
Conditions for an index column are the same as the conditions that can define constraints. Only the properties that exist at the bottom of an object type's containment can be specified as an index column. In this case, it can be defined with a period (.)
[Example 6.9] Creating an Index in an Object Column
CREATE INDEX cust_idx_1 ON customer3 (cust_obj.custno);
A function-based index cannot be created if a function's return type is an object type. When invoking the member method of a function of an object type while defining the function-based index of an object table, the table alias can be defined with a period as shown below.
[Example 6.10] Creating a Function-based Index in an Object Table
CREATE INDEX cust_idx_2 ON customer_type_tab2 x (x.tostring());
Use the dot notation if a table column is an object type and the user wants to select this object's property value. Take the following caution when using the dot donation in a SELECT statement: when using the dot notation in an object column, make sure that the table alias comes after the dot notation.
[Example 6.11] Select when the Column in the Table is an Object Type
SELECT cust_obj.phone FROM customer3; -- Incorrect SELECT x.cust_obj.phone FROM customer3 x; -- Correct
The VALUE(x) expression that takes each table's table alias as an argument in an SQL statement, and then returns the row object that corresponds to the current row.
[Example 6.12] VALUE(x) Expression
INSERT INTO customer_type_tab2 values (1, 'David', '555-666-7777'); DECLARE c1 customer_type2; BEGIN SELECT VALUE(x) into c1 FROM customer_type_tab2 x where custno = 1; dbms_output.put_line(c1.tostring()); END; /
As in the above example where the users are not viewing an object table's property value but rather invoking each member method, a VALUE(x) expression is required. When an UPDATE statement is executed as follows, a (VALUE) expression can be used for overwriting an object table's existing object with an object the user-defined constructor created. This is shown in the following example.
[Example 6.13] An Update Using a VALUE(x) Expression
CREATE OR REPLACE TYPE customer_type3 AS OBJECT ( custno NUMBER, name VARCHAR2(40), phone VARCHAR2(20), CONSTRUCTOR FUNCTION customer_type3 RETURN SELF AS RESULT); / CREATE OR REPLACE TYPE BODY customer_type3 AS CONSTRUCTOR FUNCTION customer_type3 RETURN SELF AS RESULT IS BEGIN custno := -1; name := 'Untitled'; phone := 'N/A'; RETURN; END; END; / CREATE TABLE customer_type_tab3 OF customer_type3; INSERT INTO customer_type_tab3 values (1, 'David', '555-666-7777'); UPDATE customer_type_tab3 x SET VALUE(x) = customer_type3() WHERE custno = 1;
An object type's method can be a PSM function or procedure, and specifies the operations to be performed on the object.
Provides an application with access to the data of an object's instance. The user defines a member method in the object type for each operation that the user wants an object of that type to perform an operation.
Invoked on the object type, instead of its instances. It is used for operations that are global to the type, and do not require referencing of the data of a specific object instance.
A function for returning a new instance of a user-defined type, as well as setting up the values of its attributes. It can be system-defined or user-defined.
The following is an example of invoking the member method of an object.
SELECT x.cust_obj.tostring() FROM customer x;
When a function or procedure performs operations based on the values of a given object, a member method is used to define these operations.
As in a MEMBER FUNCTION or MEMBER PROCEDURE, specify the MEMBER in front when defining a member method within a CREATE TYPE statement. A member method defined like this can be invoked by using the dot notation after an object expression as shown in the following example.
The object expression which contains the value of the object comes before the dot. After the dot, specify the name of the member method which is defined in the object type of the object. When invoking a member method in SQL, the user should always put parentheses around it, even if there are no parameters to pass to the method.
Member methods are always assumed to have a single parameter set as the first parameter. This parameter is called a SELF parameter. In a SELF parameter, the value of the target object specified when the member method is called is sent as the value of the parameter.
The user can specify this SELF parameter as the first parameter when defining the member method. However, even if not specified, it is automatically assumed to have been specified. Therefore, no syntax error is generated.
When specifying the target object's property value in the type's body, it can specified using the SELF parameter as well as the dot notation, although unnecessary for specification (as long as the parameter and the name do not overlap).
[Example 6.16] Creating a SELF Parameter
CREATE OR REPLACE TYPE rectangle_type AS OBJECT ( x NUMBER, y NUMBER, MEMBER FUNCTION around RETURN NUMBER, MEMBER FUNCTION area(SELF IN OUT NOCOPY rectangle_type) RETURN NUMBER); / CREATE OR REPLACE TYPE BODY rectangle_type AS MEMBER FUNCTION around RETURN NUMBER IS BEGIN RETURN 2 * (x + y); END; MEMBER FUNCTION area RETURN NUMBER IS BEGIN RETURN SELF.x * SELF.y; END; END; /
As shown in the following example, the user can invoke a member method of an object stored in an object table by using the dot notation.
As well, it can be done using a VALUE(x) expression which represents a row object.
[Example 6.17] Invoking a Member Method
CREATE TABLE rect_tab of rectangle_type; INSERT INTO rect_tab VALUES(2, 4); INSERT INTO rect_tab VALUES(rectangle_type(8, 3)); SELECT x.around(), x.area() FROM rect_tab x; SELECT VALUE(x).around(), VALUE(x).area() FROM rect_tab x;
To compare or sort objects, the object type in which the two objects are based on must be the same. A comparison operation is performed using a member method of a set type. If such member method does not exist, then an error is generated. However, equal and unequal comparisons are allowed through special rules. There are two types of methods for performing comparisons, map method and order method. Only one of these can be defined for a single object type.
Returns a built-in type value, and is used for comparing or sorting objects based on this value. If the user uses ORDER BY in an SQL statement for an object expression, then this map method is automatically invoked for each object.
When a map method is defined, if column "c1" and column "c2" in an SQL statement corresponds to the object type, then SQL statement is executed as follows.
SELECT 1 FROM t1 x WHERE x.c1 > x.c2;
SELECT 1 FROM t1 x WHERE x.c1.map() > x.c2.map();
The following is an example of defining a map method in an object type in order to perform a comparison operation.
[Example 6.18] Defining a Map Method in an Object Type
CREATE OR REPLACE TYPE rectangle_type AS OBJECT ( x NUMBER, y NUMBER, MAP MEMBER FUNCTION area RETURN NUMBER); / CREATE OR REPLACE TYPE BODY rectangle_type AS MAP MEMBER FUNCTION area RETURN NUMBER IS BEGIN RETURN SELF.x * SELF.y; END; END; /
Takes two objects to be compared as parameters and returns the comparison result. The first object is sent through the SELF parameter, and so only the remaining objects to be compared with the SELF parameter can be sent as additional parameters. The order method is invoked automatically for object comparison through comparison operators, but not for ORDER BY.
The return value of the order method should return a negative, zero, and positive numeric value. These values mean that each SELF object is less than, equal to, or greater than the object it compares to.
[Example 6.19] Order Method
CREATE OR REPLACE TYPE address_type AS OBJECT ( name VARCHAR(20), addr VARCHAR(50), city VARCHAR(20), state VARCHAR(2), zip VARCHAR(5), ORDER MEMBER FUNCTION cmp(v address_type) RETURN NUMBER); / CREATE OR REPLACE TYPE BODY address_type AS ORDER MEMBER FUNCTION cmp(v address_type) RETURN NUMBER IS BEGIN IF SELF.zip < v.zip THEN RETURN -1; ELSIF SELF.zip > v.zip THEN RETURN 1; ELSIF state < v.state THEN RETURN -1; ELSIF state > v.state THEN RETURN 1; ELSIF city < v.city THEN RETURN -1; ELSIF city > v.city THEN RETURN 1; ELSIF addr < v.addr THEN RETURN -1; ELSIF addr > v.addr THEN RETURN 1; ELSE RETURN 0; END IF; END; END; /
If the user performs an equal or an unequal operation even though neither the map method nor the order method exists, then this comparison compares each of the properties that exist at the bottom of the containment tree (built-in type properties) of the object type, and assumes that the results are considered to be the same as those combined with the AND operation and are executed normally.
Therefore, if the following SQL statement is executed in the case the order method in the above address_type is not defined, it is executed as follows.
[Example 6.20] Comparing Methods
SELECT 1 FROM t1 x WHERE x.c1 = x.c2;
SELECT 1 FROM t1 x WHERE x.c1.name = x.c2.name AND x.c1.addr = x.c2.addr AND x.c1.city = x.c2.city AND x.c1.state = x.c2.state AND x.c1.zip = x.c2.zip;
A static method does not define operations to be performed on a particular object, but is simply a function or procedure defined within an object type. Therefore, there are no predefined SELF parameters in static methods. To invoke a static method, precede the object type name with a dot before the method name.
The constructor method is a function that returns an object of that type as a result of execution. There are two types: predefined default constructor and user-defined constructor.
The default constructor is a parameter of the constructor. It invokes by specifying the property values of the object type in order.
The following is an example of invoking the default constructor for the above address_type.
[Example 6.22] Default Constructor
address_type("Bob", "123 Oak Street", "Los Angeles", "CA", "90143")
The user-defined constructor method is a method function that the user defines directly in the object type to create an object of that type. When defining a user-defined constructor, one can freely define which parameters to pass. If the user does not specify a value for a particular property in the constructor, the value of the property is NULL.
The definition of a custom constructor method begins with the CONSTRUCTOR FUNCTION and ends with RETURN SELF AS RESULT, as shown in the following example.
The name of the constructor must match the name of the object type.
[Example 6.23] User-defined Constructor Method
CREATE OR REPLACE TYPE rectangle_type AS OBJECT ( x NUMBER, y NUMBER, CONSTRUCTOR FUNCTION rectangle_type ( SELF IN OUT NOCOPY rectangle_type, n NUMBER) RETURN SELF AS RESULT); / CREATE OR REPLACE TYPE BODY rectangle_type AS CONSTRUCTOR FUNCTION rectangle_type( SELF IN OUT NOCOPY rectangle_type, n NUMBER) RETURN SELF AS RESULT IS BEGIN SELF.x := n; y := n; RETURN; END; END; /
The first parameter of a user-defined constructor method can specify the SELF parameter, just like a member method. Even when unspecified, it is assumed to be specified. The BODY section of the method determines the value of this SELF object variable, and is the function is terminated, the method must be terminated by using a single RETURN statement. The value of the object created by the user-defined constructor is the value of this SELF object variable.
This section describes the behaviors of Tibero objects.
Since an object consists of a set of properties, and each property can also be an object, once the object type is defined, it can be represented by a single tree representing the relationships between objects. Properties placed in a terminal in a tree cannot be an object type property, and are properties having a built-in type.
When an object is stored in a table, an object is not stored as a single value, but is stored in the tree as a tear-off value for each value of the built-in type properties located in the terminal. In other words, a column in the table where an object is stored cannot be a column for the object itself, and the object is stored by using multiple columns that consists of built-in type columns and variable array columns such as NUMBER and VARCHAR2.
When creating a table, if the type of the column specified by the user is an object type, Tibero makes these built-in type columns in the form of hidden columns and adds one more column. This column contains information about which of the objects that make up this particular object are NULL and which is not NULL. However, information about whether the built-in type attribute is NULL is stored in a hidden column for the built-in type, rather than in the NULL indicator column. In the case of an object table, a column of the object table is created for each property that make up an object type in which the object table is based, and the name of the column follows the name of the property.
If the specific property of the base type object is an object type property, then hidden columns are added as in the case of a user specifying a column of an object type in a table.
When accessing an object in the object table using the VALUE (x) expression in an object table. This object creates objects using the default constructor from the object at the bottom of the object's containment tree. Lastly, an object of the object table is created by collecting top-level objects and built-in type property values and invoking the default constructor of the final object type.
If the default constructor is obscured by the user (the type and number of parameters, and the constructor whose order is the same as the default constructor), objects are still created by using the default constructor defined in the system.
An object identifier can be used to uniquely identify an object stored in the object table. The object identifier can select either an auto-generated type or a primary key type when creating an object table.
Unless specified by the user, an auto-generated type object identifier is allocated as a hidden column (OID column) in the object table. Whenever inserting an object in an object table, a globally unique 16 bytes value that considers distributed environments is generated, and this value is stored as the value of the OIC column. This is equivalent to the DEFAULT value of the OID column when CREATE TABLE is declared with the SYS_GUID () built-in function.
If the user specifies a primary key when creating an object table, one can use it as an object identifier for the object table. An object table that is created by adding the OBJECT IDENTIFIER IS PRIMARY KEY clause to the CREATE TABLE statement does not create an auto-generated OID column, but uses the value of the primary key as the value of the object identifier
Since a primary key object identifier is based on the primary key value of the corresponding table, uniquess is guaranteed only within that object table. The length of the primary key being less than 16 bytes means that space is saved.
When a VARRAY is stored as a column of a table, it is actually stored as a single column. The maximum length of a VARRAY type value is a value obtained by multiplying the maximum length of the element type by the maximum number of elements of the VARRAY type, with some added overhead.
If the maximum possible length of the VARRAY type value exceeds the maximum length of VARCHAR2, a LOB segment is also created, which allows storing of the VARRAY value with a long length when creating a table with this VARRAY column. However, when storing the actual value, if the value is smaller than the maximum length of VARCHAR2 for each value regardless of the existence of the LOB segment, it is stored in the table as it is, otherwise, it is stored in the LOB segment.
The following is a description of how the main constructor works.
Masking a Constructor
If the user defines a constructor that looks exactly like the default constructor, the default constructor cannot be invoked by the user, and is masked by the user-defined constructor. User-defined constructors are not inherited by subtypes, so they are not masked by constructors defined by subtypes.
Overloading a Constructor
As with generic type methods, constructors can be overloaded. This means that there can be multiple constructors to create objects of a particular object type at the same time.
Using a Constructor
A constructor is a type of expression, and a constructor can be used where general columns and functions can be used. To invoke a constructor in SQL, one must always put parentheses in it, even if there are no arguments to the constructor. The user can specify SELF when defining a constructor, but cannot specify a parameter that corresponds to SELF when the user calls it. The DEFAULT clause of the CREATE TABLE or ALTER TABLE and CHECK constraints cannot come with a user-defined constructor, only the default constructor.